diff options
112 files changed, 2129 insertions, 1294 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java index f1403bd51049..e833bb95a302 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java @@ -439,7 +439,7 @@ public class JobParameters implements Parcelable { * provides an easy way to tell whether the job is being executed due to the deadline * expiring. Note: If the job is running because its deadline expired, it implies that its * constraints will not be met. However, - * {@link android.app.job.JobInfo.Builder#setPeriodic(boolean) periodic jobs} will only ever + * {@link android.app.job.JobInfo.Builder#setPeriodic(long) periodic jobs} will only ever * run when their constraints are satisfied, therefore, the constraints will still be satisfied * for a periodic job even if the deadline has expired. */ diff --git a/api/javadoc-lint-baseline b/api/javadoc-lint-baseline index c28480e4f11a..d9e72b83e46e 100644 --- a/api/javadoc-lint-baseline +++ b/api/javadoc-lint-baseline @@ -53,16 +53,6 @@ android/adservices/ondevicepersonalization/WebViewEventInput.java:21: lint: Unre android/adservices/ondevicepersonalization/WebViewEventInput.java:30: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.WebViewEventInput [101] android/adservices/ondevicepersonalization/WebViewEventInput.java:41: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.EventUrlProvider#createEventTrackingUrlWithResponse() EventUrlProvider#createEventTrackingUrlWithResponse()" in android.adservices.ondevicepersonalization.WebViewEventInput [101] android/adservices/ondevicepersonalization/WebViewEventOutput.java:21: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onWebViewEvent() IsolatedWorker#onWebViewEvent()" in android.adservices.ondevicepersonalization.WebViewEventOutput [101] -android/app/ActivityOptions.java:366: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101] -android/app/ActivityOptions.java:370: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101] -android/app/ActivityOptions.java:384: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101] -android/app/ApplicationStartInfo.java:96: lint: Unresolved link/see tag "#START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE" in android.app.ApplicationStartInfo [101] -android/app/BroadcastOptions.java:132: lint: Unresolved link/see tag "#setDeliveryGroupMatchingFilter(android.content.IntentFilter)" in android.app.BroadcastOptions [101] -android/app/GrammaticalInflectionManager.java:60: lint: Unresolved link/see tag "android.os.Environment#getDataSystemCeDirectory(int)" in android.app.GrammaticalInflectionManager [101] -android/app/Notification.java:509: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.app.Notification [101] -android/app/Notification.java:650: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.app.Notification [101] -android/app/Notification.java:1866: lint: Unresolved link/see tag "/*missing*/" in android.app.Notification.Action [101] -android/app/Notification.java:4796: lint: Unresolved link/see tag "android.content.pm.ShortcutInfo#setLongLived() ShortcutInfo#setLongLived()" in android.app.Notification.MessagingStyle [101] android/app/admin/DevicePolicyManager.java:2670: lint: Unresolved link/see tag "android.os.UserManager#DISALLOW_CAMERA UserManager#DISALLOW_CAMERA" in android.app.admin.DevicePolicyManager [101] android/app/admin/DevicePolicyManager.java:7257: lint: Unresolved link/see tag "android.app.admin.DevicePolicyIdentifiers#USB_DATA_SIGNALING_POLICY DevicePolicyIdentifiers#USB_DATA_SIGNALING_POLICY" in android.app.admin.DevicePolicyManager [101] android/app/admin/DevicePolicyManager.java:7425: lint: Unresolved link/see tag "ACTION_DEVICE_FINANCING_STATE_CHANGED" in android.app.admin.DevicePolicyManager [101] @@ -83,17 +73,6 @@ android/app/appsearch/SearchSpec.java:244: lint: Unresolved link/see tag "Featur android/app/appsearch/SearchSpec.java:913: lint: Unresolved link/see tag "Features#NUMERIC_SEARCH" in android.app.appsearch.SearchSpec.Builder [101] android/app/appsearch/SearchSpec.java:925: lint: Unresolved link/see tag "Features#VERBATIM_SEARCH" in android.app.appsearch.SearchSpec.Builder [101] android/app/appsearch/SearchSpec.java:929: lint: Unresolved link/see tag "Features#LIST_FILTER_QUERY_LANGUAGE" in android.app.appsearch.SearchSpec.Builder [101] -android/app/job/JobParameters.java:128: lint: Unresolved link/see tag "android.app.job.JobInfo.Builder#setPeriodic(boolean) periodic jobs" in android.app.job.JobParameters [101] -android/app/sdksandbox/AppOwnedSdkSandboxInterface.java:9: lint: Unresolved link/see tag "SdkSandboxController#getAppOwnedSdkSandboxInterfaces" in android.app.sdksandbox.AppOwnedSdkSandboxInterface [101] -android/app/sdksandbox/SdkSandboxManager.java:112: lint: Unresolved link/see tag "AppOwnedSdkSandboxInterfaces" in android.app.sdksandbox.SdkSandboxManager [101] -android/content/AttributionSource.java:291: lint: Unresolved link/see tag "setNextAttributionSource" in android.content.AttributionSource.Builder [101] -android/content/Context.java:2872: lint: Unresolved link/see tag "android.telephony.MmsManager" in android.content.Context [101] -android/content/Intent.java:4734: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101] -android/content/Intent.java:4760: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101] -android/content/Intent.java:4778: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101] -android/content/Intent.java:4802: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101] -android/graphics/Paint.java:838: lint: Unresolved link/see tag "android.annotation.ColorLong ColorLong" in android.graphics.Paint [101] -android/graphics/text/LineBreaker.java:246: lint: Unresolved link/see tag "StaticLayout.Builder#setUseBoundsForWidth(boolean)" in android.graphics.text.LineBreaker.Builder [101] android/hardware/camera2/CameraCharacteristics.java:2169: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101] android/hardware/camera2/CameraCharacteristics.java:2344: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101] android/hardware/camera2/CameraCharacteristics.java:2344: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations tables" in android.hardware.camera2.CameraCharacteristics [101] @@ -119,11 +98,6 @@ android/hardware/camera2/CaptureRequest.java:704: lint: Unresolved link/see tag android/hardware/camera2/CaptureRequest.java:1501: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureRequest [101] android/hardware/camera2/CaptureResult.java:923: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureResult [101] android/hardware/camera2/CaptureResult.java:2337: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureResult [101] -android/hardware/input/InputManager.java:215: lint: Unresolved link/see tag "android.hardware.input.InputManagerGlobal#getInputDevice InputManagerGlobal#getInputDevice" in android.hardware.input.InputManager.InputDeviceListener [101] -android/inputmethodservice/AbstractInputMethodService.java:155: lint: Unresolved link/see tag "android.app.ActivityThread ActivityThread" in android.inputmethodservice.AbstractInputMethodService [101] -android/inputmethodservice/InputMethodService.java:1078: lint: Unresolved link/see tag "android.widget.Editor" in android.inputmethodservice.InputMethodService [101] -android/location/GnssSignalType.java:14: lint: Unresolved link/see tag "android.location.GnssStatus.ConstellationType GnssStatus.ConstellationType" in android.location.GnssSignalType [101] -android/location/GnssSignalType.java:48: lint: Unresolved link/see tag "android.location.GnssStatus.ConstellationType GnssStatus.ConstellationType" in android.location.GnssSignalType [101] android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ALARM AttributeSdkUsage#USAGE_ALARM" in android.media.AudioAttributes.Builder [101] android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ASSISTANCE_ACCESSIBILITY AttributeSdkUsage#USAGE_ASSISTANCE_ACCESSIBILITY" in android.media.AudioAttributes.Builder [101] android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE AttributeSdkUsage#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" in android.media.AudioAttributes.Builder [101] @@ -177,26 +151,6 @@ android/net/wifi/aware/SubscribeConfig.java:51: lint: Unresolved link/see tag "a android/net/wifi/aware/SubscribeConfig.java:51: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.SubscribeConfig [101] android/net/wifi/aware/SubscribeConfig.java:276: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.SubscribeConfig.Builder [101] android/net/wifi/aware/SubscribeConfig.java:276: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.SubscribeConfig.Builder [101] -android/os/BugreportManager.java:146: lint: Unresolved link/see tag "android.os.BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT" in android.os.BugreportManager.BugreportCallback [101] -android/os/PowerManager.java:796: lint: Unresolved link/see tag "android.os.Temperature" in android.os.PowerManager.OnThermalStatusChangedListener [101] -android/os/RemoteException.java:49: lint: Unresolved link/see tag "android.os.DeadSystemRuntimeException DeadSystemRuntimeException" in android.os.RemoteException [101] -android/provider/Settings.java:374: lint: Unresolved link/see tag "android.credentials.CredentialManager#isEnabledCredentialProviderService()" in android.provider.Settings [101] -android/provider/Settings.java:908: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService" in android.provider.Settings [101] -android/provider/Settings.java:2181: lint: Unresolved link/see tag "android.app.time.TimeManager" in android.provider.Settings.Global [101] -android/provider/Settings.java:2195: lint: Unresolved link/see tag "android.app.time.TimeManager" in android.provider.Settings.Global [101] -android/security/KeyStoreException.java:27: lint: Unresolved link/see tag "android.security.KeyStoreException.PublicErrorCode PublicErrorCode" in android.security.KeyStoreException [101] -android/service/autofill/FillResponse.java:86: lint: Unresolved link/see tag "setFieldClassificationIds" in android.service.autofill.FillResponse.Builder [101] -android/service/autofill/SaveInfo.java:623: lint: Unresolved link/see tag "FillRequest.getHints()" in android.service.autofill.SaveInfo.Builder [101] -android/service/notification/NotificationListenerService.java:417: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService notification assistant" in android.service.notification.NotificationListenerService [101] -android/service/notification/NotificationListenerService.java:435: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService notification assistant" in android.service.notification.NotificationListenerService [101] -android/service/notification/NotificationListenerService.java:1155: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService NotificationAssistantService" in android.service.notification.NotificationListenerService.Ranking [101] -android/service/notification/NotificationListenerService.java:1166: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService NotificationAssistantService" in android.service.notification.NotificationListenerService.Ranking [101] -android/service/quickaccesswallet/WalletCard.java:285: lint: Unresolved link/see tag "PackageManager.FEATURE_WALLET_LOCATION_BASED_SUGGESTIONS" in android.service.quickaccesswallet.WalletCard.Builder [101] -android/service/voice/VoiceInteractionSession.java:293: lint: Unresolved link/see tag "android.service.voice.VoiceInteractionService#KEY_SHOW_SESSION_ID VoiceInteractionService#KEY_SHOW_SESSION_ID" in android.service.voice.VoiceInteractionSession [101] -android/text/DynamicLayout.java:141: lint: Unresolved link/see tag "LineBreakconfig" in android.text.DynamicLayout [101] -android/text/WordSegmentFinder.java:13: lint: Unresolved link/see tag "android.text.method.WordIterator WordIterator" in android.text.WordSegmentFinder [101] -android/view/PixelCopy.java:468: lint: Unresolved link/see tag "android.view.PixelCopy.CopyResultStatus CopyResultStatus" in android.view.PixelCopy.Result [101] -android/window/BackEvent.java:24: lint: Unresolved link/see tag "android.window.BackMotionEvent BackMotionEvent" in android.window.BackEvent [101] android/net/wifi/SoftApConfiguration.java:173: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)" in android.net.wifi.SoftApConfiguration [101] android/os/UserManager.java:2384: lint: Unresolved link/see tag "android.annotation.UserHandleAware @UserHandleAware" in android.os.UserManager [101] @@ -218,8 +172,3 @@ com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/se com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/see tag "PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean)" in android [101] com/android/server/pm/PackageInstallerSession.java:358: lint: Unresolved link/see tag "IntentSender" in android [101] com/android/server/devicepolicy/DevicePolicyManagerService.java:860: lint: Unresolved link/see tag "android.security.IKeyChainService#setGrant" in android [101] - -android/os/BatteryStatsManager.java:260: lint: Invalid tag: @Deprecated [131] -android/os/BatteryStatsManager.java:275: lint: Invalid tag: @Deprecated [131] - -java/lang/ClassLoader.java:853: lint: Unknown tag: @systemProperty [103] diff --git a/core/api/current.txt b/core/api/current.txt index 6c0fccc87198..dfe023a3c181 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android { public final class Manifest { @@ -5741,6 +5739,7 @@ package android.app { ctor @Deprecated public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet); ctor @Deprecated public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet, int); method @Deprecated public void onBackStackChanged(); + method @Deprecated protected void onLayout(boolean, int, int, int, int); method @Deprecated public void setActivity(android.app.Activity); method @Deprecated public void setMaxVisible(int); method @Deprecated public void setOnBreadCrumbClickListener(android.app.FragmentBreadCrumbs.OnBreadCrumbClickListener); @@ -13653,6 +13652,7 @@ package android.content.res { public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet java.lang.AutoCloseable { method public void close(); + method public String getAttributeNamespace(int); } } @@ -20405,7 +20405,7 @@ package android.inputmethodservice { method @Deprecated public boolean isPreviewEnabled(); method @Deprecated public boolean isProximityCorrectionEnabled(); method @Deprecated public boolean isShifted(); - method public void onClick(android.view.View); + method @Deprecated public void onClick(android.view.View); method @Deprecated public void onDetachedFromWindow(); method @Deprecated public void onDraw(android.graphics.Canvas); method @Deprecated protected boolean onLongPress(android.inputmethodservice.Keyboard.Key); @@ -24232,7 +24232,7 @@ package android.media { @Deprecated public class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor { method @Deprecated public void apply(); - method public Object clone() throws java.lang.CloneNotSupportedException; + method @Deprecated public Object clone() throws java.lang.CloneNotSupportedException; method @Deprecated public android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException; method @Deprecated public android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException; method @Deprecated public android.media.RemoteControlClient.MetadataEditor putObject(int, Object) throws java.lang.IllegalArgumentException; @@ -27096,6 +27096,7 @@ package android.media.tv { method @NonNull public java.util.List<android.media.AudioPresentation> getAudioPresentations(); method public String getSelectedTrack(int); method public java.util.List<android.media.tv.TvTrackInfo> getTracks(int); + method protected void onLayout(boolean, int, int, int, int); method public boolean onUnhandledInputEvent(android.view.InputEvent); method public void overrideTvAppAttributionSource(@NonNull android.content.AttributionSource); method public void reset(); @@ -43549,7 +43550,6 @@ package android.telephony { method public int getLongitude(); method public int getNetworkId(); method public int getSystemId(); - method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR; } @@ -43565,7 +43565,6 @@ package android.telephony { method @Nullable public String getMncString(); method @Nullable public String getMobileNetworkOperator(); method @Deprecated public int getPsc(); - method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityGsm> CREATOR; } @@ -43583,7 +43582,6 @@ package android.telephony { method @Nullable public String getMobileNetworkOperator(); method public int getPci(); method public int getTac(); - method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityLte> CREATOR; } @@ -43596,7 +43594,6 @@ package android.telephony { method @IntRange(from=0, to=3279165) public int getNrarfcn(); method @IntRange(from=0, to=1007) public int getPci(); method @IntRange(from=0, to=16777215) public int getTac(); - method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityNr> CREATOR; } @@ -43610,7 +43607,6 @@ package android.telephony { method @Nullable public String getMncString(); method @Nullable public String getMobileNetworkOperator(); method public int getUarfcn(); - method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityTdscdma> CREATOR; } @@ -43626,7 +43622,6 @@ package android.telephony { method @Nullable public String getMobileNetworkOperator(); method public int getPsc(); method public int getUarfcn(); - method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR; } @@ -43710,6 +43705,7 @@ package android.telephony { public final class CellSignalStrengthCdma extends android.telephony.CellSignalStrength implements android.os.Parcelable { method public int describeContents(); + method public boolean equals(Object); method public int getAsuLevel(); method public int getCdmaDbm(); method public int getCdmaEcio(); @@ -43720,24 +43716,28 @@ package android.telephony { method public int getEvdoLevel(); method public int getEvdoSnr(); method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); + method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthCdma> CREATOR; } public final class CellSignalStrengthGsm extends android.telephony.CellSignalStrength implements android.os.Parcelable { method public int describeContents(); + method public boolean equals(Object); method public int getAsuLevel(); method public int getBitErrorRate(); method public int getDbm(); method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); method public int getRssi(); method public int getTimingAdvance(); + method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR; } public final class CellSignalStrengthLte extends android.telephony.CellSignalStrength implements android.os.Parcelable { method public int describeContents(); + method public boolean equals(Object); method public int getAsuLevel(); method @IntRange(from=0, to=15) public int getCqi(); method @IntRange(from=1, to=6) public int getCqiTableIndex(); @@ -43748,12 +43748,14 @@ package android.telephony { method public int getRssi(); method public int getRssnr(); method public int getTimingAdvance(); + method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthLte> CREATOR; } public final class CellSignalStrengthNr extends android.telephony.CellSignalStrength implements android.os.Parcelable { method public int describeContents(); + method public boolean equals(Object); method public int getAsuLevel(); method @IntRange(from=0, to=15) @NonNull public java.util.List<java.lang.Integer> getCsiCqiReport(); method @IntRange(from=1, to=3) public int getCsiCqiTableIndex(); @@ -43766,26 +43768,31 @@ package android.telephony { method public int getSsRsrq(); method public int getSsSinr(); method @IntRange(from=0, to=1282) public int getTimingAdvanceMicros(); + method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthNr> CREATOR; } public final class CellSignalStrengthTdscdma extends android.telephony.CellSignalStrength implements android.os.Parcelable { method public int describeContents(); + method public boolean equals(Object); method public int getAsuLevel(); method public int getDbm(); method @IntRange(from=0, to=4) public int getLevel(); method public int getRscp(); + method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthTdscdma> CREATOR; } public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable { method public int describeContents(); + method public boolean equals(Object); method public int getAsuLevel(); method public int getDbm(); method public int getEcNo(); method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel(); + method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR; } @@ -46573,6 +46580,7 @@ package android.text { method @Deprecated public int length(); method @Deprecated public static android.text.AlteredCharSequence make(CharSequence, char[], int, int); method @Deprecated public CharSequence subSequence(int, int); + method @Deprecated public String toString(); } @Deprecated public class AndroidCharacter { @@ -47024,6 +47032,7 @@ package android.text { method public void removeSpan(Object); method public void setSpan(Object, int, int, int); method public CharSequence subSequence(int, int); + method public String toString(); } public static final class PrecomputedText.Params { @@ -47153,6 +47162,7 @@ package android.text { method public void setFilters(android.text.InputFilter[]); method public void setSpan(Object, int, int, int); method public CharSequence subSequence(int, int); + method public String toString(); method public static android.text.SpannableStringBuilder valueOf(CharSequence); } @@ -48793,7 +48803,9 @@ package android.util { method public boolean containsValue(Object); method public void ensureCapacity(int); method public java.util.Set<java.util.Map.Entry<K,V>> entrySet(); + method public boolean equals(@Nullable Object); method public V get(Object); + method public int hashCode(); method public int indexOfKey(Object); method public int indexOfValue(Object); method public boolean isEmpty(); @@ -48825,7 +48837,9 @@ package android.util { method public boolean contains(Object); method public boolean containsAll(java.util.Collection<?>); method public void ensureCapacity(int); + method public boolean equals(@Nullable Object); method public void forEach(java.util.function.Consumer<? super E>); + method public int hashCode(); method public int indexOf(Object); method public boolean isEmpty(); method public java.util.Iterator<E> iterator(); @@ -57564,6 +57578,7 @@ package android.widget { ctor @Deprecated public AbsoluteLayout(android.content.Context, android.util.AttributeSet); ctor @Deprecated public AbsoluteLayout(android.content.Context, android.util.AttributeSet, int); ctor @Deprecated public AbsoluteLayout(android.content.Context, android.util.AttributeSet, int, int); + method @Deprecated protected void onLayout(boolean, int, int, int, int); } @Deprecated public static class AbsoluteLayout.LayoutParams extends android.view.ViewGroup.LayoutParams { @@ -57642,6 +57657,7 @@ package android.widget { method public long getSelectedItemId(); method public int getSelectedItemPosition(); method public abstract android.view.View getSelectedView(); + method protected void onLayout(boolean, int, int, int, int); method public boolean performItemClick(android.view.View, int, long); method public abstract void setAdapter(T); method public void setEmptyView(android.view.View); @@ -58288,6 +58304,7 @@ package android.widget { method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet); method @Deprecated public boolean getConsiderGoneChildrenWhenMeasuring(); method public boolean getMeasureAllChildren(); + method protected void onLayout(boolean, int, int, int, int); method public void setMeasureAllChildren(boolean); } @@ -58341,6 +58358,7 @@ package android.widget { method public boolean getUseDefaultMargins(); method public boolean isColumnOrderPreserved(); method public boolean isRowOrderPreserved(); + method protected void onLayout(boolean, int, int, int, int); method public void setAlignmentMode(int); method public void setColumnCount(int); method public void setColumnOrderPreserved(boolean); @@ -58563,6 +58581,7 @@ package android.widget { method public float getWeightSum(); method public boolean isBaselineAligned(); method public boolean isMeasureWithLargestChildEnabled(); + method protected void onLayout(boolean, int, int, int, int); method public void setBaselineAligned(boolean); method public void setBaselineAlignedChildIndex(int); method public void setDividerDrawable(android.graphics.drawable.Drawable); @@ -59111,6 +59130,7 @@ package android.widget { method public android.widget.RelativeLayout.LayoutParams generateLayoutParams(android.util.AttributeSet); method public int getGravity(); method public int getIgnoreGravity(); + method protected void onLayout(boolean, int, int, int, int); method public void setGravity(int); method public void setHorizontalGravity(int); method public void setIgnoreGravity(int); @@ -59565,6 +59585,7 @@ package android.widget { method @Deprecated public boolean isMoving(); method @Deprecated public boolean isOpened(); method @Deprecated public void lock(); + method @Deprecated protected void onLayout(boolean, int, int, int, int); method @Deprecated public void open(); method @Deprecated public void setOnDrawerCloseListener(android.widget.SlidingDrawer.OnDrawerCloseListener); method @Deprecated public void setOnDrawerOpenListener(android.widget.SlidingDrawer.OnDrawerOpenListener); @@ -60211,6 +60232,7 @@ package android.widget { method public boolean hideOverflowMenu(); method public void inflateMenu(@MenuRes int); method public boolean isOverflowMenuShowing(); + method protected void onLayout(boolean, int, int, int, int); method public void setCollapseContentDescription(@StringRes int); method public void setCollapseContentDescription(@Nullable CharSequence); method public void setCollapseIcon(@DrawableRes int); @@ -60365,7 +60387,7 @@ package android.widget { method @Deprecated public android.view.View getZoomControls(); method @Deprecated public boolean isAutoDismissed(); method @Deprecated public boolean isVisible(); - method public boolean onTouch(android.view.View, android.view.MotionEvent); + method @Deprecated public boolean onTouch(android.view.View, android.view.MotionEvent); method @Deprecated public void setAutoDismissed(boolean); method @Deprecated public void setFocusable(boolean); method @Deprecated public void setOnZoomListener(android.widget.ZoomButtonsController.OnZoomListener); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 500a12cacc3b..b5d3ed7c8a7e 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android { public static final class Manifest.permission { diff --git a/core/api/module-lib-removed.txt b/core/api/module-lib-removed.txt index 14191ebcb080..d802177e249b 100644 --- a/core/api/module-lib-removed.txt +++ b/core/api/module-lib-removed.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/core/api/removed.txt b/core/api/removed.txt index e2b4e4dfc6c4..5a4be65ef559 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android.app { public class Notification implements android.os.Parcelable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 1f20cb9c26f9..3bc868d9a71d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android { public static final class Manifest.permission { @@ -4061,7 +4059,9 @@ package android.content.pm { } public static final class PackageManager.UninstallCompleteCallback implements android.os.Parcelable { + method public int describeContents(); method public void onUninstallComplete(@NonNull String, int, @Nullable String); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PackageManager.UninstallCompleteCallback> CREATOR; } @@ -5961,6 +5961,7 @@ package android.hardware.soundtrigger { public static final class SoundTrigger.Keyphrase implements android.os.Parcelable { ctor public SoundTrigger.Keyphrase(int, int, @NonNull java.util.Locale, @NonNull String, @Nullable int[]); + method public int describeContents(); method public int getId(); method @NonNull public java.util.Locale getLocale(); method public int getRecognitionModes(); @@ -5983,6 +5984,7 @@ package android.hardware.soundtrigger { public static final class SoundTrigger.KeyphraseSoundModel extends android.hardware.soundtrigger.SoundTrigger.SoundModel implements android.os.Parcelable { ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[], int); ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[]); + method public int describeContents(); method @NonNull public android.hardware.soundtrigger.SoundTrigger.Keyphrase[] getKeyphrases(); method @NonNull public static android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel readFromParcel(@NonNull android.os.Parcel); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -5990,6 +5992,7 @@ package android.hardware.soundtrigger { } public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable { + method public int describeContents(); method public int getEnd(); method public int getStart(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -6800,6 +6803,7 @@ package android.media.musicrecognition { public abstract class MusicRecognitionService extends android.app.Service { ctor public MusicRecognitionService(); + method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void onRecognize(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.media.musicrecognition.MusicRecognitionService.Callback); } @@ -6858,6 +6862,7 @@ package android.media.soundtrigger { public abstract class SoundTriggerDetectionService extends android.app.Service { ctor public SoundTriggerDetectionService(); + method public final android.os.IBinder onBind(android.content.Intent); method @MainThread public void onConnected(@NonNull java.util.UUID, @Nullable android.os.Bundle); method @MainThread public void onDisconnected(@NonNull java.util.UUID, @Nullable android.os.Bundle); method @MainThread public void onError(@NonNull java.util.UUID, @Nullable android.os.Bundle, int, int); @@ -7571,6 +7576,7 @@ package android.media.tv.tuner.filter { } public class MediaEvent extends android.media.tv.tuner.filter.FilterEvent { + method protected void finalize(); method public long getAudioHandle(); method @NonNull public java.util.List<android.media.AudioPresentation> getAudioPresentations(); method public long getAvDataId(); @@ -8965,6 +8971,8 @@ package android.net { package android.net.metrics { @Deprecated public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event { + method @Deprecated public int describeContents(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); } @Deprecated public static final class ApfProgramEvent.Builder { @@ -8979,6 +8987,8 @@ package android.net.metrics { } @Deprecated public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event { + method @Deprecated public int describeContents(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); } @Deprecated public static final class ApfStats.Builder { @@ -8997,6 +9007,8 @@ package android.net.metrics { } @Deprecated public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event { + method @Deprecated public int describeContents(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); } @Deprecated public static final class DhcpClientEvent.Builder { @@ -9008,7 +9020,9 @@ package android.net.metrics { @Deprecated public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event { ctor @Deprecated public DhcpErrorEvent(int); + method @Deprecated public int describeContents(); method @Deprecated public static int errorCodeWithOption(int, int); + method @Deprecated public void writeToParcel(android.os.Parcel, int); field @Deprecated public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000 field @Deprecated public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000 field @Deprecated public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000 @@ -9046,6 +9060,8 @@ package android.net.metrics { @Deprecated public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event { ctor @Deprecated public IpManagerEvent(int, long); + method @Deprecated public int describeContents(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); field @Deprecated public static final int COMPLETE_LIFECYCLE = 3; // 0x3 field @Deprecated public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8 field @Deprecated public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7 @@ -9058,6 +9074,8 @@ package android.net.metrics { @Deprecated public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event { ctor @Deprecated public IpReachabilityEvent(int); + method @Deprecated public int describeContents(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); field @Deprecated public static final int NUD_FAILED = 512; // 0x200 field @Deprecated public static final int NUD_FAILED_ORGANIC = 1024; // 0x400 field @Deprecated public static final int PROBE = 256; // 0x100 @@ -9068,6 +9086,8 @@ package android.net.metrics { @Deprecated public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event { ctor @Deprecated public NetworkEvent(int, long); ctor @Deprecated public NetworkEvent(int); + method @Deprecated public int describeContents(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); field @Deprecated public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4 field @Deprecated public static final int NETWORK_CONNECTED = 1; // 0x1 field @Deprecated public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc @@ -9084,6 +9104,8 @@ package android.net.metrics { } @Deprecated public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event { + method @Deprecated public int describeContents(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); } @Deprecated public static final class RaEvent.Builder { @@ -9098,7 +9120,9 @@ package android.net.metrics { } @Deprecated public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event { + method @Deprecated public int describeContents(); method @Deprecated @NonNull public static String getProbeName(int); + method @Deprecated public void writeToParcel(android.os.Parcel, int); field @Deprecated public static final int DNS_FAILURE = 0; // 0x0 field @Deprecated public static final int DNS_SUCCESS = 1; // 0x1 field @Deprecated public static final int PROBE_DNS = 0; // 0x0 @@ -11503,6 +11527,7 @@ package android.service.assist.classification { public abstract class FieldClassificationService extends android.app.Service { ctor public FieldClassificationService(); + method public final android.os.IBinder onBind(android.content.Intent); method public abstract void onClassificationRequest(@NonNull android.service.assist.classification.FieldClassificationRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.assist.classification.FieldClassificationResponse,java.lang.Exception>); method public void onConnected(); method public void onDisconnected(); @@ -11581,6 +11606,7 @@ package android.service.autofill.augmented { method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]); method protected void dump(@NonNull java.io.PrintWriter, @NonNull String[]); method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory(); + method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); method public void onFillRequest(@NonNull android.service.autofill.augmented.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.augmented.FillController, @NonNull android.service.autofill.augmented.FillCallback); @@ -11619,6 +11645,7 @@ package android.service.autofill.augmented { public final class FillWindow implements java.lang.AutoCloseable { ctor public FillWindow(); + method public void close(); method public void destroy(); method public boolean update(@NonNull android.service.autofill.augmented.PresentationParams.Area, @NonNull android.view.View, long); } @@ -11644,6 +11671,7 @@ package android.service.carrier { public final class CarrierMessagingServiceWrapper implements java.lang.AutoCloseable { ctor public CarrierMessagingServiceWrapper(); method public boolean bindToCarrierMessagingService(@NonNull android.content.Context, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull Runnable); + method public void close(); method public void disconnect(); method public void downloadMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback); method public void receiveSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback); @@ -11694,6 +11722,7 @@ package android.service.contentcapture { method public final void disableSelf(); method public void onActivityEvent(@NonNull android.service.contentcapture.ActivityEvent); method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData); + method public final android.os.IBinder onBind(android.content.Intent); 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); @@ -11732,6 +11761,7 @@ package android.service.contentsuggestions { public abstract class ContentSuggestionsService extends android.app.Service { ctor public ContentSuggestionsService(); + method public final android.os.IBinder onBind(android.content.Intent); method public abstract void onClassifyContentSelections(@NonNull android.app.contentsuggestions.ClassificationsRequest, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback); method public abstract void onNotifyInteraction(@NonNull String, @NonNull android.os.Bundle); method public abstract void onProcessContextImage(int, @Nullable android.graphics.Bitmap, @NonNull android.os.Bundle); @@ -11745,6 +11775,7 @@ package android.service.dataloader { public abstract class DataLoaderService extends android.app.Service { ctor public DataLoaderService(); + method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); method @Nullable public android.service.dataloader.DataLoaderService.DataLoader onCreateDataLoader(@NonNull android.content.pm.DataLoaderParams); } @@ -12417,6 +12448,7 @@ package android.service.tracing { public class TraceReportService extends android.app.Service { ctor public TraceReportService(); + method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); method public void onReportTrace(@NonNull android.service.tracing.TraceReportService.TraceParams); } @@ -13042,6 +13074,7 @@ package android.telecom { method @Nullable public android.content.ComponentName getCallScreeningComponent(); method public boolean isBlocked(); method public boolean isInContacts(); + method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telecom.Connection.CallFilteringCompletionInfo> CREATOR; } @@ -13351,6 +13384,7 @@ package android.telephony { method public int getReason(); method public int getTimeoutSeconds(); method public boolean isEnabled(); + method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR; field public static final int REASON_ALL = 4; // 0x4 field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5 @@ -13635,6 +13669,7 @@ package android.telephony { method public int getDownlinkCapacityKbps(); method public int getType(); method public int getUplinkCapacityKbps(); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.LinkCapacityEstimate> CREATOR; field public static final int INVALID = -1; // 0xffffffff field public static final int LCE_TYPE_COMBINED = 2; // 0x2 @@ -13644,8 +13679,10 @@ package android.telephony { public final class LteVopsSupportInfo extends android.telephony.VopsSupportInfo { ctor public LteVopsSupportInfo(int, int); + method public boolean equals(@Nullable Object); method public int getEmcBearerSupport(); method public int getVopsSupport(); + method public int hashCode(); method public boolean isEmergencyServiceFallbackSupported(); method public boolean isEmergencyServiceSupported(); method public boolean isVopsSupported(); @@ -13746,9 +13783,11 @@ package android.telephony { public final class NrVopsSupportInfo extends android.telephony.VopsSupportInfo { ctor public NrVopsSupportInfo(int, int, int); + method public boolean equals(@Nullable Object); method public int getEmcSupport(); method public int getEmfSupport(); method public int getVopsSupport(); + method public int hashCode(); method public boolean isEmergencyServiceFallbackSupported(); method public boolean isEmergencyServiceSupported(); method public boolean isVopsSupported(); @@ -14861,6 +14900,7 @@ package android.telephony.data { public abstract class QualifiedNetworksService extends android.app.Service { ctor public QualifiedNetworksService(); + method public android.os.IBinder onBind(android.content.Intent); method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int); field public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService"; } @@ -15052,6 +15092,7 @@ package android.telephony.gba { public class GbaService extends android.app.Service { ctor public GbaService(); method public void onAuthenticationRequest(int, int, int, @NonNull android.net.Uri, @NonNull byte[], boolean); + method public android.os.IBinder onBind(android.content.Intent); method public final void reportAuthenticationFailure(int, int) throws java.lang.RuntimeException; method public final void reportKeysAvailable(int, @NonNull byte[], @NonNull String) throws java.lang.RuntimeException; field public static final String SERVICE_INTERFACE = "android.telephony.gba.GbaService"; @@ -15554,6 +15595,7 @@ package android.telephony.ims { method @Deprecated public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int); method @NonNull public android.telephony.ims.stub.ImsRegistrationImplBase getRegistrationForSubscription(int, int); method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int); + method public android.os.IBinder onBind(android.content.Intent); method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException; method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures(); method public void readyForFeatureCreation(); diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt index 1fa2718dc6d2..aa17df3471d7 100644 --- a/core/api/system-removed.txt +++ b/core/api/system-removed.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android.app { public class AppOpsManager { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index eeddeb21aa9d..0e857a9c5f93 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android { public static final class Manifest.permission { @@ -3946,7 +3944,9 @@ package android.widget.inline { package android.window { public final class BackNavigationInfo implements android.os.Parcelable { + method public int describeContents(); method @NonNull public static String typeToString(int); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.window.BackNavigationInfo> CREATOR; field public static final String KEY_TRIGGER_BACK = "TriggerBack"; field public static final int TYPE_CALLBACK = 4; // 0x4 @@ -4007,11 +4007,13 @@ package android.window { } public final class TaskFragmentCreationParams implements android.os.Parcelable { + method public int describeContents(); method @NonNull public android.os.IBinder getFragmentToken(); method @NonNull public android.graphics.Rect getInitialRelativeBounds(); method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizer(); method @NonNull public android.os.IBinder getOwnerToken(); method public int getWindowingMode(); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentCreationParams> CREATOR; } @@ -4023,6 +4025,7 @@ package android.window { } public final class TaskFragmentInfo implements android.os.Parcelable { + method public int describeContents(); method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo); method @NonNull public java.util.List<android.os.IBinder> getActivities(); method @NonNull public java.util.List<android.os.IBinder> getActivitiesRequestedInTaskFragment(); @@ -4036,6 +4039,7 @@ package android.window { method public boolean isEmpty(); method public boolean isTaskClearedForReuse(); method public boolean isVisible(); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentInfo> CREATOR; } @@ -4058,6 +4062,8 @@ package android.window { } public final class TaskFragmentOrganizerToken implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentOrganizerToken> CREATOR; } diff --git a/core/api/test-removed.txt b/core/api/test-removed.txt index 14191ebcb080..d802177e249b 100644 --- a/core/api/test-removed.txt +++ b/core/api/test-removed.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 895dde760058..f2c00517ad16 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -2073,9 +2073,7 @@ public class ActivityOptions extends ComponentOptions { * Allow a {@link PendingIntent} to use the privilege of its creator to start background * activities. * - * @param mode the {@link android.app.ComponentOptions.BackgroundActivityStartMode} being set - * @throws IllegalArgumentException is the value is not a valid - * {@link android.app.ComponentOptions.BackgroundActivityStartMode} + * @param mode the mode being set */ @NonNull public ActivityOptions setPendingIntentCreatorBackgroundActivityStartMode( @@ -2088,7 +2086,7 @@ public class ActivityOptions extends ComponentOptions { * Returns the mode to start background activities granted by the creator of the * {@link PendingIntent}. * - * @return the {@link android.app.ComponentOptions.BackgroundActivityStartMode} currently set + * @return the mode currently set */ public @BackgroundActivityStartMode int getPendingIntentCreatorBackgroundActivityStartMode() { return mPendingIntentCreatorBackgroundActivityStartMode; diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index 9549ebf698a8..41b400459526 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -843,8 +843,7 @@ public class BroadcastOptions extends ComponentOptions { * considered to be in the same delivery group as this iff it has the same {@code namespace} * and {@code key}. * - * <p> If neither matching key using this API nor matching filter using - * {@link #setDeliveryGroupMatchingFilter(IntentFilter)} is specified, then by default + * <p> If not matching key using this API then by default * {@link Intent#filterEquals(Intent)} will be used to identify the delivery group. */ @NonNull diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 8fea03ba47f5..ebf183ff18c3 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -50,7 +50,6 @@ import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.security.net.config.NetworkSecurityConfigProvider; -import android.sysprop.VndkProperties; import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.ArrayMap; @@ -901,14 +900,10 @@ public final class LoadedApk { } // Similar to vendor apks, we should add /product/lib for apks from product partition - // when product apps are marked as unbundled. We cannot use the same way from vendor - // to check if lib path exists because there is possibility that /product/lib would not - // exist from legacy device while product apks are bundled. To make this clear, we use - // "ro.product.vndk.version" property. If the property is defined, we regard all product - // apks as unbundled. + // when product apps are marked as unbundled. Product is separated as long as the + // partition exists, so it can be handled with same approach from the vendor partition. if (mApplicationInfo.getCodePath() != null - && mApplicationInfo.isProduct() - && VndkProperties.product_vndk_version().isPresent()) { + && mApplicationInfo.isProduct()) { isBundledApp = false; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index dd7db23d668b..94e1292a7554 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1514,13 +1514,13 @@ public class Notification implements Parcelable /** * {@link #extras} key: the color used as a hint for the Answer action button of a - * {@link android.app.Notification.CallStyle} notification. This extra is a {@link ColorInt}. + * {@link android.app.Notification.CallStyle} notification. This extra is a {@code ColorInt}. */ public static final String EXTRA_ANSWER_COLOR = "android.answerColor"; /** * {@link #extras} key: the color used as a hint for the Decline or Hang Up action button of a - * {@link android.app.Notification.CallStyle} notification. This extra is a {@link ColorInt}. + * {@link android.app.Notification.CallStyle} notification. This extra is a {@code ColorInt}. */ public static final String EXTRA_DECLINE_COLOR = "android.declineColor"; @@ -1704,7 +1704,7 @@ public class Notification implements Parcelable private static final String EXTRA_DATA_ONLY_INPUTS = "android.extra.DATA_ONLY_INPUTS"; /** - * {@link }: No semantic action defined. + * No semantic action defined. */ public static final int SEMANTIC_ACTION_NONE = 0; @@ -7923,7 +7923,7 @@ public class Notification implements Parcelable * (via {@link Notification.Builder#setShortcutId(String)}) are displayed in a dedicated * conversation section in the shade above non-conversation alerting and silence notifications. * To be a valid conversation shortcut, the shortcut must be a - * {@link ShortcutInfo#setLongLived()} dynamic or cached sharing shortcut. + * {@link ShortcutInfo.Builder#setLongLived(boolean)} dynamic or cached sharing shortcut. * * <p> * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior. diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index bfc1eec829e8..20eae9ade429 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -730,7 +730,7 @@ public final class AttributionSource implements Parcelable { /** * The next app to receive the permission protected data. * - * @deprecated Use {@link setNextAttributionSource} instead. + * @deprecated Use {@link #setNextAttributionSource} instead. */ @Deprecated public @NonNull Builder setNext(@Nullable AttributionSource value) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index b6a98a5b8f83..884351b57045 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4357,7 +4357,6 @@ public abstract class Context { * @see android.telephony.CarrierConfigManager * @see #EUICC_SERVICE * @see android.telephony.euicc.EuiccManager - * @see android.telephony.MmsManager * @see #INPUT_METHOD_SERVICE * @see android.view.inputmethod.InputMethodManager * @see #UI_MODE_SERVICE diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 5f4c05f001ff..1eb2cd174a7f 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4180,7 +4180,7 @@ public class Intent implements Parcelable, Cloneable { * new state of quiet mode. This is only sent to registered receivers, not manifest receivers. * * <p>This broadcast is similar to {@link #ACTION_MANAGED_PROFILE_AVAILABLE} but functions as a - * generic broadcast for all users of type {@link android.content.pm.UserInfo#isProfile()}}. + * generic broadcast for all profile users. */ @FlaggedApi(FLAG_ALLOW_PRIVATE_PROFILE) public static final String ACTION_PROFILE_AVAILABLE = @@ -4194,7 +4194,7 @@ public class Intent implements Parcelable, Cloneable { * new state of quiet mode. This is only sent to registered receivers, not manifest receivers. * * <p>This broadcast is similar to {@link #ACTION_MANAGED_PROFILE_UNAVAILABLE} but functions as - * a generic broadcast for all users of type {@link android.content.pm.UserInfo#isProfile()}}. + * a generic broadcast for all profile users. */ @FlaggedApi(FLAG_ALLOW_PRIVATE_PROFILE) public static final String ACTION_PROFILE_UNAVAILABLE = @@ -4222,7 +4222,7 @@ public class Intent implements Parcelable, Cloneable { * that was removed. * * <p>This broadcast is similar to {@link #ACTION_MANAGED_PROFILE_REMOVED} but functions as a - * generic broadcast for all users of type {@link android.content.pm.UserInfo#isProfile()}}. + * generic broadcast for all profile users. * It is sent in addition to the {@link #ACTION_MANAGED_PROFILE_REMOVED} broadcast when a * managed user is removed. * @@ -4242,7 +4242,7 @@ public class Intent implements Parcelable, Cloneable { * that was added. * * <p>This broadcast is similar to {@link #ACTION_MANAGED_PROFILE_ADDED} but functions as a - * generic broadcast for all users of type {@link android.content.pm.UserInfo#isProfile()}}. + * generic broadcast for all profile users. * It is sent in addition to the {@link #ACTION_MANAGED_PROFILE_ADDED} broadcast when a * managed user is added. * diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index ff1a6acd8e4e..7b8419e6c6f7 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1373,7 +1373,7 @@ public final class InputManager { public interface InputDeviceListener { /** * Called whenever an input device has been added to the system. - * Use {@link InputManagerGlobal#getInputDevice} to get more information about the device. + * Use {@link #getInputDevice(int)} to get more information about the device. * * @param deviceId The id of the input device that was added. */ diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 582c5c0c4dd4..4c2bbc18f2db 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -3231,7 +3231,7 @@ public class InputMethodService extends AbstractInputMethodService { } /** - * Called when the user tapped or clicked an {@link android.widget.Editor}. + * Called when the user tapped or clicked an editor. * This can be useful when IME makes a decision of showing Virtual keyboard based on what * {@link MotionEvent#getToolType(int)} was used to click the editor. * e.g. when toolType is {@link MotionEvent#TOOL_TYPE_STYLUS}, IME may choose to show a diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index 086b0e5d4b05..58def6ef7961 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -143,10 +143,11 @@ public final class BugreportManager { */ public void onError(@BugreportErrorCode int errorCode) {} - /** Called when taking bugreport finishes successfully. + /** + * Called when taking bugreport finishes successfully. * * <p>This callback will be invoked if the - * {@link BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT} flag is not set. + * {@code BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT} flag is not set. */ public void onFinished() {} diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 4174c1c13c94..fce715ade5af 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -2670,7 +2670,7 @@ public final class PowerManager { /** * Called when overall thermal throttling status changed. - * @param status defined in {@link android.os.Temperature}. + * @param status the status */ void onThermalStatusChanged(@ThermalStatus int status); } diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java index 970f4192c36c..ace5f7e8393f 100644 --- a/core/java/android/os/RemoteException.java +++ b/core/java/android/os/RemoteException.java @@ -66,7 +66,7 @@ public class RemoteException extends AndroidException { /** * Rethrow this exception when we know it came from the system server. This * gives us an opportunity to throw a nice clean - * {@link DeadSystemRuntimeException} signal to avoid spamming logs with + * {@code DeadSystemRuntimeException} signal to avoid spamming logs with * misleading stack traces. * <p> * Apps making calls into the system server may end up persisting internal diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b19a034d4628..b34e09f2c97a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1800,7 +1800,6 @@ public final class Settings { * Input: Nothing. * <p> * Output: Nothing. - * @see android.service.notification.NotificationAssistantService */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_NOTIFICATION_ASSISTANT_SETTINGS = @@ -2507,8 +2506,8 @@ public final class Settings { * to the caller package. * <p> * <b>NOTE: </b> Applications should call - * {@link android.credentials.CredentialManager#isEnabledCredentialProviderService()} - * and only use this action to start an activity if they return {@code false}. + * {@link android.credentials.CredentialManager#isEnabledCredentialProviderService( + * ComponentName)} and only use this action to start an activity if they return {@code false}. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_CREDENTIAL_PROVIDER = @@ -12375,7 +12374,7 @@ public final class Settings { * Value to specify if the device's UTC system clock should be set automatically, e.g. using * telephony signals like NITZ, or other sources like GNSS or NTP. * - * <p>Prefer {@link android.app.time.TimeManager} API calls to determine the state of + * <p>Prefer {@code android.app.time.TimeManager} API calls to determine the state of * automatic time detection instead of directly observing this setting as it may be ignored * by the time_detector service under various conditions. * @@ -12388,7 +12387,7 @@ public final class Settings { * Value to specify if the device's time zone system property should be set automatically, * e.g. using telephony signals like MCC and NITZ, or other mechanisms like the location. * - * <p>Prefer {@link android.app.time.TimeManager} API calls to determine the state of + * <p>Prefer {@code android.app.time.TimeManager} API calls to determine the state of * automatic time zone detection instead of directly observing this setting as it may be * ignored by the time_zone_detector service under various conditions. * diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index 3fb94ee93c14..7ea74d375ffb 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -406,7 +406,7 @@ public final class FillResponse implements Parcelable { * * Call this when a field has been detected with a type. * - * Altough similiarly named with {@link setFieldClassificationIds}, + * Altough similiarly named with {@link #setFieldClassificationIds}, * it provides a different functionality - setFieldClassificationIds should * be used when a field is only suspected to be Autofillable. * This method should be used when a field is certainly Autofillable diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 954cc960665f..53706cd3f887 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -813,7 +813,7 @@ public final class SaveInfo implements Parcelable { * If no {@link #Builder(int, AutofillId[]) required ids}, * or {@link #setOptionalIds(AutofillId[]) optional ids}, or {@link #FLAG_DELAY_SAVE} * were set, Save Dialog will only be triggered if platform detection is enabled, which - * is indicated when {@link FillRequest.getHints()} is not empty. + * is indicated when {@link FillRequest#getHints()} is not empty. */ public SaveInfo build() { throwIfDestroyed(); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 1cfff14b2d7c..759953e4aca4 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -896,8 +896,7 @@ public abstract class NotificationListenerService extends Service { * <p>This method will throw a security exception if you don't have access to notifications * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated - * device} or be the {@link NotificationAssistantService notification assistant} in order to - * use this method. + * device} or be the notification assistant in order to use this method. * * @param pkg The package to retrieve channels for. */ @@ -920,8 +919,7 @@ public abstract class NotificationListenerService extends Service { * <p>This method will throw a security exception if you don't have access to notifications * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated - * device} or be the {@link NotificationAssistantService notification assistant} in order to - * use this method. + * device} or be the notification assistant in order to use this method. * * @param pkg The package to retrieve channel groups for. */ @@ -2001,7 +1999,7 @@ public abstract class NotificationListenerService extends Service { /** * Returns a list of smart {@link Notification.Action} that can be added by the - * {@link NotificationAssistantService} + * notification assistant. */ public @NonNull List<Notification.Action> getSmartActions() { return mSmartActions == null ? Collections.emptyList() : mSmartActions; @@ -2022,8 +2020,7 @@ public abstract class NotificationListenerService extends Service { } /** - * Returns a list of smart replies that can be added by the - * {@link NotificationAssistantService} + * Returns a list of smart replies that can be added by the notification assistant. */ public @NonNull List<CharSequence> getSmartReplies() { return mSmartReplies == null ? Collections.emptyList() : mSmartReplies; diff --git a/core/java/android/service/quickaccesswallet/WalletCard.java b/core/java/android/service/quickaccesswallet/WalletCard.java index 4a4fd041fb19..bf129c551605 100644 --- a/core/java/android/service/quickaccesswallet/WalletCard.java +++ b/core/java/android/service/quickaccesswallet/WalletCard.java @@ -372,9 +372,9 @@ public final class WalletCard implements Parcelable { } /** - * Set of locations this card might be useful at. If {@link - * PackageManager.FEATURE_WALLET_LOCATION_BASED_SUGGESTIONS} is enabled, the card might be - * shown to the user when a user is near one of these locations. + * Set of locations this card might be useful at. If + * {@link android.content.pm.PackageManager#FEATURE_WALLET_LOCATION_BASED_SUGGESTIONS} is + * enabled, the card might be shown to the user when a user is near one of these locations. */ @NonNull public Builder setCardLocations(@NonNull List<Location> cardLocations) { diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index cabcae30851f..d40b39e18edb 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -1809,7 +1809,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * in milliseconds of the KeyEvent that triggered Assistant and * Intent.EXTRA_ASSIST_INPUT_DEVICE_ID (android.intent.extra.ASSIST_INPUT_DEVICE_ID) * referring to the device that sent the request. Starting from Android 14, the system will - * add {@link VoiceInteractionService#KEY_SHOW_SESSION_ID}, the Bundle is not null. But the + * add {@link #KEY_SHOW_SESSION_ID}, the Bundle is not null. But the * application should handle null case before Android 14. * @param showFlags The show flags originally provided to * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}. diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 8862f1d74ab1..a0cd0748f509 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -1274,7 +1274,7 @@ public class DynamicLayout extends Layout { } /** - * Gets the {@link LineBreakconfig} used in this DynamicLayout. + * Gets the {@link LineBreakConfig} used in this DynamicLayout. * Use this only to consult the LineBreakConfig's properties and not * to change them. * diff --git a/core/java/android/text/WordSegmentFinder.java b/core/java/android/text/WordSegmentFinder.java index be002f3102d3..b0a70eae902a 100644 --- a/core/java/android/text/WordSegmentFinder.java +++ b/core/java/android/text/WordSegmentFinder.java @@ -24,7 +24,7 @@ import android.text.method.WordIterator; /** * Implementation of {@link SegmentFinder} using words as the text segment. Word boundaries are - * found using {@link WordIterator}. Whitespace characters are excluded, so they are not included in + * found using {@code WordIterator}. Whitespace characters are excluded, so they are not included in * any text segments. * * <p>For example, the text "Hello, World!" would be subdivided into four text segments: "Hello", diff --git a/core/java/android/window/BackEvent.java b/core/java/android/window/BackEvent.java index f53737abf707..55623608b025 100644 --- a/core/java/android/window/BackEvent.java +++ b/core/java/android/window/BackEvent.java @@ -49,7 +49,7 @@ public final class BackEvent { private final int mSwipeEdge; /** - * Creates a new {@link BackMotionEvent} instance. + * Creates a new {@link BackEvent} instance. * * @param touchX Absolute X location of the touch point of this event. * @param touchY Absolute Y location of the touch point of this event. diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java index 611da3cec5c6..0cbfcc501918 100644 --- a/core/java/android/window/WindowProviderService.java +++ b/core/java/android/window/WindowProviderService.java @@ -155,7 +155,7 @@ public abstract class WindowProviderService extends Service implements WindowPro } /** - * Override {@link Service}'s empty implementation and listen to {@link ActivityThread} for + * Override {@link Service}'s empty implementation and listen to {@code ActivityThread} for * low memory and trim memory events. */ @Override diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 7c931cd9fa15..9caf87f32b8e 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -13,3 +13,10 @@ flag { description: "On close to square display, when necessary, configuration includes status bar" bug: "291870756" } + +flag { + name: "dimmer_refactor" + namespace: "windowing_frontend" + description: "Refactor dim to fix flickers" + bug: "281632483,295291019" +}
\ No newline at end of file diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index ec525f09fa88..4bb7c33b41e2 100644 --- a/core/java/com/android/internal/protolog/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -91,6 +91,8 @@ public enum ProtoLogGroup implements IProtoLogGroup { WM_DEBUG_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, "CoreBackPreview"), WM_DEBUG_DREAM(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM), + + WM_DEBUG_DIMMER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagerProtoLogTest"); private final boolean mEnabled; diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 9c6528785584..b71aaf3fc2e6 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1801,6 +1801,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-504637678": { + "message": "Starting animation on dim layer %s, requested by %s, alpha: %f -> %f, blur: %d -> %d", + "level": "VERBOSE", + "group": "WM_DEBUG_DIMMER", + "at": "com\/android\/server\/wm\/SmoothDimmer.java" + }, "-503656156": { "message": "Update process config of %s to new config %s", "level": "VERBOSE", @@ -3739,6 +3745,12 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityClientController.java" }, + "1309365288": { + "message": "Removing dim surface %s on transaction %s", + "level": "DEBUG", + "group": "WM_DEBUG_DIMMER", + "at": "com\/android\/server\/wm\/SmoothDimmer.java" + }, "1316533291": { "message": "State movement: %s from:%s to:%s reason:%s", "level": "VERBOSE", @@ -4003,6 +4015,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1620751818": { + "message": "Dim %s skipping animation and directly setting alpha=%f, blur=%d", + "level": "DEBUG", + "group": "WM_DEBUG_DIMMER", + "at": "com\/android\/server\/wm\/SmoothDimmer.java" + }, "1621562070": { "message": " startWCT=%s", "level": "VERBOSE", @@ -4560,6 +4578,9 @@ "WM_DEBUG_CONTENT_RECORDING": { "tag": "WindowManager" }, + "WM_DEBUG_DIMMER": { + "tag": "WindowManager" + }, "WM_DEBUG_DRAW": { "tag": "WindowManager" }, diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index db1cc446b2d6..9fde0fd6e6ab 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1609,7 +1609,7 @@ public class Paint { /** * Returns the color of the shadow layer. * - * @return the shadow layer's color encoded as a {@link ColorLong}. + * @return the shadow layer's color encoded as a {@code ColorLong}. * @see #setShadowLayer(float,float,float,int) * @see #setShadowLayer(float,float,float,long) * @see Color diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java index dc2e794a1df4..0e3fb163ef75 100644 --- a/graphics/java/android/graphics/text/LineBreaker.java +++ b/graphics/java/android/graphics/text/LineBreaker.java @@ -249,7 +249,7 @@ public class LineBreaker { * @param useBoundsForWidth True for using bounding box, false for advances. * @return this builder instance * @see Layout#getUseBoundsForWidth() - * @see StaticLayout.Builder#setUseBoundsForWidth(boolean) + * @see android.text.StaticLayout.Builder#setUseBoundsForWidth(boolean) */ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public @NonNull Builder setUseBoundsForWidth(boolean useBoundsForWidth) { diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java index 0e198d5c56ec..e6de5978ceb0 100644 --- a/graphics/java/android/view/PixelCopy.java +++ b/graphics/java/android/view/PixelCopy.java @@ -322,7 +322,7 @@ public final class PixelCopy { } /** - * Returns the {@link CopyResultStatus} of the copy request. + * Returns the status of the copy request. */ public @CopyResultStatus int getStatus() { return mStatus; diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java index 253d70465720..5825facee021 100644 --- a/keystore/java/android/security/KeyStoreException.java +++ b/keystore/java/android/security/KeyStoreException.java @@ -319,7 +319,7 @@ public class KeyStoreException extends Exception { /** * Returns one of the error codes exported by the class. * - * @return a public error code, one of the values in {@link PublicErrorCode}. + * @return a public error code */ @PublicErrorCode public int getNumericErrorCode() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index c508d55507b8..8a6403705c1c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -17,19 +17,13 @@ package com.android.wm.shell.dagger.pip; import android.annotation.NonNull; -import android.content.Context; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; -import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; -import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipTransition; -import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; @@ -48,21 +42,8 @@ public abstract class Pip2Module { @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull Transitions transitions, PipBoundsState pipBoundsState, - PipBoundsAlgorithm pipBoundsAlgorithm, - PipController pipController) { + PipBoundsAlgorithm pipBoundsAlgorithm) { return new PipTransition(shellInit, shellTaskOrganizer, transitions, pipBoundsState, null, pipBoundsAlgorithm); } - - @WMSingleton - @Provides - static PipController providePipController(Context context, - ShellInit shellInit, - ShellController shellController, - DisplayController displayController, - DisplayInsetsController displayInsetsController, - PipDisplayLayoutState pipDisplayLayoutState) { - return PipController.create(context, shellInit, shellController, displayController, - displayInsetsController, pipDisplayLayoutState); - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java deleted file mode 100644 index 186cb615f4ec..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2023 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.wm.shell.pip2.phone; - -import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; - -import android.content.Context; -import android.content.res.Configuration; -import android.view.InsetsState; - -import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.DisplayInsetsController; -import com.android.wm.shell.common.DisplayLayout; -import com.android.wm.shell.common.pip.PipDisplayLayoutState; -import com.android.wm.shell.common.pip.PipUtils; -import com.android.wm.shell.protolog.ShellProtoLogGroup; -import com.android.wm.shell.sysui.ConfigurationChangeListener; -import com.android.wm.shell.sysui.ShellController; -import com.android.wm.shell.sysui.ShellInit; - -/** - * Manages the picture-in-picture (PIP) UI and states for Phones. - */ -public class PipController implements ConfigurationChangeListener, - DisplayController.OnDisplaysChangedListener { - private static final String TAG = PipController.class.getSimpleName(); - - private Context mContext; - private ShellController mShellController; - private DisplayController mDisplayController; - private DisplayInsetsController mDisplayInsetsController; - private PipDisplayLayoutState mPipDisplayLayoutState; - - private PipController(Context context, - ShellInit shellInit, - ShellController shellController, - DisplayController displayController, - DisplayInsetsController displayInsetsController, - PipDisplayLayoutState pipDisplayLayoutState) { - mContext = context; - mShellController = shellController; - mDisplayController = displayController; - mDisplayInsetsController = displayInsetsController; - mPipDisplayLayoutState = pipDisplayLayoutState; - - if (PipUtils.isPip2ExperimentEnabled()) { - shellInit.addInitCallback(this::onInit, this); - } - } - - private void onInit() { - // Ensure that we have the display info in case we get calls to update the bounds before the - // listener calls back - mPipDisplayLayoutState.setDisplayId(mContext.getDisplayId()); - DisplayLayout layout = new DisplayLayout(mContext, mContext.getDisplay()); - mPipDisplayLayoutState.setDisplayLayout(layout); - - mShellController.addConfigurationChangeListener(this); - mDisplayController.addDisplayWindowListener(this); - mDisplayInsetsController.addInsetsChangedListener(mPipDisplayLayoutState.getDisplayId(), - new DisplayInsetsController.OnInsetsChangedListener() { - @Override - public void insetsChanged(InsetsState insetsState) { - onDisplayChanged(mDisplayController - .getDisplayLayout(mPipDisplayLayoutState.getDisplayId())); - } - }); - } - - /** - * Instantiates {@link PipController}, returns {@code null} if the feature not supported. - */ - public static PipController create(Context context, - ShellInit shellInit, - ShellController shellController, - DisplayController displayController, - DisplayInsetsController displayInsetsController, - PipDisplayLayoutState pipDisplayLayoutState) { - if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { - ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: Device doesn't support Pip feature", TAG); - return null; - } - return new PipController(context, shellInit, shellController, displayController, - displayInsetsController, pipDisplayLayoutState); - } - - - @Override - public void onConfigurationChanged(Configuration newConfiguration) { - mPipDisplayLayoutState.onConfigurationChanged(); - } - - @Override - public void onThemeChanged() { - onDisplayChanged(new DisplayLayout(mContext, mContext.getDisplay())); - } - - @Override - public void onDisplayAdded(int displayId) { - if (displayId != mPipDisplayLayoutState.getDisplayId()) { - return; - } - onDisplayChanged(mDisplayController.getDisplayLayout(displayId)); - } - - @Override - public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { - if (displayId != mPipDisplayLayoutState.getDisplayId()) { - return; - } - onDisplayChanged(mDisplayController.getDisplayLayout(displayId)); - } - - private void onDisplayChanged(DisplayLayout layout) { - mPipDisplayLayoutState.setDisplayLayout(layout); - } -} diff --git a/libs/hwui/api/current.txt b/libs/hwui/api/current.txt index 794082124344..c396a2032eed 100644 --- a/libs/hwui/api/current.txt +++ b/libs/hwui/api/current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android.graphics { public class ColorMatrix { diff --git a/libs/hwui/api/module-lib-current.txt b/libs/hwui/api/module-lib-current.txt index 14191ebcb080..d802177e249b 100644 --- a/libs/hwui/api/module-lib-current.txt +++ b/libs/hwui/api/module-lib-current.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/libs/hwui/api/module-lib-removed.txt b/libs/hwui/api/module-lib-removed.txt index 14191ebcb080..d802177e249b 100644 --- a/libs/hwui/api/module-lib-removed.txt +++ b/libs/hwui/api/module-lib-removed.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/libs/hwui/api/removed.txt b/libs/hwui/api/removed.txt index 14191ebcb080..d802177e249b 100644 --- a/libs/hwui/api/removed.txt +++ b/libs/hwui/api/removed.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/libs/hwui/api/system-current.txt b/libs/hwui/api/system-current.txt index 14191ebcb080..d802177e249b 100644 --- a/libs/hwui/api/system-current.txt +++ b/libs/hwui/api/system-current.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/libs/hwui/api/system-removed.txt b/libs/hwui/api/system-removed.txt index 14191ebcb080..d802177e249b 100644 --- a/libs/hwui/api/system-removed.txt +++ b/libs/hwui/api/system-removed.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/location/java/android/location/GnssSignalType.java b/location/java/android/location/GnssSignalType.java index 16c3f2ed27d8..2dd67f0c12aa 100644 --- a/location/java/android/location/GnssSignalType.java +++ b/location/java/android/location/GnssSignalType.java @@ -34,8 +34,7 @@ public final class GnssSignalType implements Parcelable { /** * Creates a {@link GnssSignalType} with a full list of parameters. * - * @param constellationType the constellation type as defined in - * {@link GnssStatus.ConstellationType} + * @param constellationType the constellation type * @param carrierFrequencyHz the carrier frequency in Hz * @param codeType the code type as defined in {@link GnssMeasurement#getCodeType()} */ @@ -66,7 +65,7 @@ public final class GnssSignalType implements Parcelable { this.mCodeType = codeType; } - /** Returns the {@link GnssStatus.ConstellationType}. */ + /** Returns the constellation type. */ @GnssStatus.ConstellationType public int getConstellationType() { return mConstellationType; diff --git a/media/java/android/media/RingtoneV1.java b/media/java/android/media/RingtoneV1.java index 3c54d4a0d166..b761afaeaa67 100644 --- a/media/java/android/media/RingtoneV1.java +++ b/media/java/android/media/RingtoneV1.java @@ -16,15 +16,14 @@ package android.media; +import android.annotation.NonNull; import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.content.res.Resources.NotFoundException; import android.media.audiofx.HapticGenerator; import android.net.Uri; import android.os.Binder; -import android.os.Build; import android.os.RemoteException; import android.os.Trace; import android.os.VibrationEffect; @@ -62,6 +61,7 @@ class RingtoneV1 implements Ringtone.ApiInterface { private final Context mContext; private final AudioManager mAudioManager; + private final Ringtone.Injectables mInjectables; private VolumeShaper.Configuration mVolumeShaperConfig; private VolumeShaper mVolumeShaper; @@ -74,12 +74,10 @@ class RingtoneV1 implements Ringtone.ApiInterface { private final IRingtonePlayer mRemotePlayer; private final Binder mRemoteToken; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private MediaPlayer mLocalPlayer; private final MyOnCompletionListener mCompletionListener = new MyOnCompletionListener(); private HapticGenerator mHapticGenerator; - @UnsupportedAppUsage private Uri mUri; private String mTitle; @@ -94,10 +92,15 @@ class RingtoneV1 implements Ringtone.ApiInterface { private boolean mHapticGeneratorEnabled = false; private final Object mPlaybackSettingsLock = new Object(); - /** {@hide} */ - @UnsupportedAppUsage + /** @hide */ public RingtoneV1(Context context, boolean allowRemote) { + this(context, new Ringtone.Injectables(), allowRemote); + } + + /** @hide */ + RingtoneV1(Context context, @NonNull Ringtone.Injectables injectables, boolean allowRemote) { mContext = context; + mInjectables = injectables; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mAllowRemote = allowRemote; mRemotePlayer = allowRemote ? mAudioManager.getRingtonePlayer() : null; @@ -200,7 +203,7 @@ class RingtoneV1 implements Ringtone.ApiInterface { } destroyLocalPlayer(); // try opening uri locally before delegating to remote player - mLocalPlayer = new MediaPlayer(); + mLocalPlayer = mInjectables.newMediaPlayer(); try { mLocalPlayer.setDataSource(mContext, mUri); mLocalPlayer.setAudioAttributes(mAudioAttributes); @@ -240,19 +243,7 @@ class RingtoneV1 implements Ringtone.ApiInterface { */ public boolean hasHapticChannels() { // FIXME: support remote player, or internalize haptic channels support and remove entirely. - try { - android.os.Trace.beginSection("Ringtone.hasHapticChannels"); - if (mLocalPlayer != null) { - for(MediaPlayer.TrackInfo trackInfo : mLocalPlayer.getTrackInfo()) { - if (trackInfo.hasHapticChannels()) { - return true; - } - } - } - } finally { - android.os.Trace.endSection(); - } - return false; + return mInjectables.hasHapticChannels(mLocalPlayer); } /** @@ -334,7 +325,7 @@ class RingtoneV1 implements Ringtone.ApiInterface { * @see android.media.audiofx.HapticGenerator#isAvailable() */ public boolean setHapticGeneratorEnabled(boolean enabled) { - if (!HapticGenerator.isAvailable()) { + if (!mInjectables.isHapticGeneratorAvailable()) { return false; } synchronized (mPlaybackSettingsLock) { @@ -362,7 +353,7 @@ class RingtoneV1 implements Ringtone.ApiInterface { mLocalPlayer.setVolume(mVolume); mLocalPlayer.setLooping(mIsLooping); if (mHapticGenerator == null && mHapticGeneratorEnabled) { - mHapticGenerator = HapticGenerator.create(mLocalPlayer.getAudioSessionId()); + mHapticGenerator = mInjectables.createHapticGenerator(mLocalPlayer); } if (mHapticGenerator != null) { mHapticGenerator.setEnabled(mHapticGeneratorEnabled); @@ -397,7 +388,6 @@ class RingtoneV1 implements Ringtone.ApiInterface { * * @hide */ - @UnsupportedAppUsage public void setUri(Uri uri) { setUri(uri, null); } @@ -425,7 +415,6 @@ class RingtoneV1 implements Ringtone.ApiInterface { } /** {@hide} */ - @UnsupportedAppUsage public Uri getUri() { return mUri; } @@ -556,7 +545,7 @@ class RingtoneV1 implements Ringtone.ApiInterface { Log.e(TAG, "Could not load fallback ringtone"); return false; } - mLocalPlayer = new MediaPlayer(); + mLocalPlayer = mInjectables.newMediaPlayer(); if (afd.getDeclaredLength() < 0) { mLocalPlayer.setDataSource(afd.getFileDescriptor()); } else { @@ -594,12 +583,12 @@ class RingtoneV1 implements Ringtone.ApiInterface { } public boolean isLocalOnly() { - return mAllowRemote; + return !mAllowRemote; } public boolean isUsingRemotePlayer() { // V2 testing api, but this is the v1 approximation. - return (mLocalPlayer == null) && mAllowRemote && (mRemotePlayer != null); + return (mLocalPlayer == null) && mAllowRemote && (mRemotePlayer != null) && (mUri != null); } class MyOnCompletionListener implements MediaPlayer.OnCompletionListener { diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml index e88655894156..7d79a6c266e4 100644 --- a/media/tests/MediaFrameworkTest/AndroidManifest.xml +++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml @@ -20,6 +20,7 @@ <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> diff --git a/media/tests/MediaFrameworkTest/AndroidTest.xml b/media/tests/MediaFrameworkTest/AndroidTest.xml index 132028ce98dc..91c92cc13d1b 100644 --- a/media/tests/MediaFrameworkTest/AndroidTest.xml +++ b/media/tests/MediaFrameworkTest/AndroidTest.xml @@ -23,5 +23,6 @@ <option name="package" value="com.android.mediaframeworktest" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> + <option name="isolated-storage" value="false"/> </test> </configuration> diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java index 9be7004c5701..30edfa40802b 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java @@ -44,7 +44,6 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner { @Override public TestSuite getAllTests() { TestSuite suite = new InstrumentationTestSuite(this); - addMediaMetadataRetrieverStateUnitTests(suite); addMediaRecorderStateUnitTests(suite); addMediaPlayerStateUnitTests(suite); addMediaScannerUnitTests(suite); @@ -70,11 +69,6 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner { } // Running all unit tests checking the state machine may be time-consuming. - private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) { - suite.addTestSuite(MediaMetadataRetrieverTest.class); - } - - // Running all unit tests checking the state machine may be time-consuming. private void addMediaRecorderStateUnitTests(TestSuite suite) { suite.addTestSuite(MediaRecorderPrepareStateUnitTest.class); suite.addTestSuite(MediaRecorderResetStateUnitTest.class); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java index bdca4744ff74..f70d2d1f8ae7 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java @@ -16,26 +16,34 @@ package com.android.mediaframeworktest.unit; +import static org.junit.Assert.assertTrue; + import android.graphics.Bitmap; import android.media.MediaMetadataRetriever; -import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; +import androidx.test.runner.AndroidJUnit4; + import com.android.mediaframeworktest.MediaNames; import com.android.mediaframeworktest.MediaProfileReader; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.FileOutputStream; import java.io.IOException; -public class MediaMetadataRetrieverTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class MediaMetadataRetrieverTest { private static final String TAG = "MediaMetadataRetrieverTest"; // Test album art extraction. @MediumTest - public static void testGetEmbeddedPicture() throws Exception { + @Test + public void testGetEmbeddedPicture() throws Exception { Log.v(TAG, "testGetEmbeddedPicture starts."); MediaMetadataRetriever retriever = new MediaMetadataRetriever(); boolean supportWMA = MediaProfileReader.getWMAEnable(); @@ -78,7 +86,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase { // Test frame capture @LargeTest - public static void testThumbnailCapture() throws Exception { + @Test + public void testThumbnailCapture() throws Exception { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); boolean supportWMA = MediaProfileReader.getWMAEnable(); boolean supportWMV = MediaProfileReader.getWMVEnable(); @@ -134,7 +143,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase { } @LargeTest - public static void testMetadataRetrieval() throws Exception { + @Test + public void testMetadataRetrieval() throws Exception { boolean supportWMA = MediaProfileReader.getWMAEnable(); boolean supportWMV = MediaProfileReader.getWMVEnable(); boolean hasFailed = false; @@ -169,7 +179,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase { // If the specified call order and valid media file is used, no exception // should be thrown. @MediumTest - public static void testBasicNormalMethodCallSequence() throws Exception { + @Test + public void testBasicNormalMethodCallSequence() throws Exception { boolean hasFailed = false; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { @@ -197,7 +208,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase { // If setDataSource() has not been called, both getFrameAtTime() and extractMetadata() must // return null. @MediumTest - public static void testBasicAbnormalMethodCallSequence() { + @Test + public void testBasicAbnormalMethodCallSequence() { boolean hasFailed = false; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); if (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM) != null) { @@ -213,7 +225,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase { // Test setDataSource() @MediumTest - public static void testSetDataSource() throws IOException { + @Test + public void testSetDataSource() throws IOException { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); boolean hasFailed = false; diff --git a/media/tests/ringtone/Android.bp b/media/tests/ringtone/Android.bp index 55b98c4704b1..8d1e5e3a5bab 100644 --- a/media/tests/ringtone/Android.bp +++ b/media/tests/ringtone/Android.bp @@ -9,15 +9,24 @@ android_test { srcs: ["src/**/*.java"], libs: [ - "android.test.runner", "android.test.base", + "android.test.mock", + "android.test.runner", ], static_libs: [ - "androidx.test.rules", - "testng", + "androidx.test.ext.junit", "androidx.test.ext.truth", + "androidx.test.rules", "frameworks-base-testutils", + "mockito-target-inline-minus-junit4", + "testables", + "testng", + ], + + jni_libs: [ + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", ], test_suites: [ diff --git a/media/tests/ringtone/OWNERS b/media/tests/ringtone/OWNERS new file mode 100644 index 000000000000..93b44f4788c5 --- /dev/null +++ b/media/tests/ringtone/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 345036 + +include /services/core/java/com/android/server/vibrator/OWNERS diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RingtoneTest.java b/media/tests/ringtone/src/com/android/media/RingtoneBuilderTest.java index 3c0c6847f557..2c8daba86d19 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RingtoneTest.java +++ b/media/tests/ringtone/src/com/android/media/RingtoneBuilderTest.java @@ -14,20 +14,22 @@ * limitations under the License. */ -package com.android.mediaframeworktest.unit; +package com.android.media; import static android.media.Ringtone.MEDIA_SOUND; import static android.media.Ringtone.MEDIA_SOUND_AND_VIBRATION; import static android.media.Ringtone.MEDIA_VIBRATION; +import static com.android.media.testing.MediaPlayerTestHelper.verifyPlayerFallbackSetup; +import static com.android.media.testing.MediaPlayerTestHelper.verifyPlayerSetup; +import static com.android.media.testing.MediaPlayerTestHelper.verifyPlayerStarted; +import static com.android.media.testing.MediaPlayerTestHelper.verifyPlayerStopped; + import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; @@ -53,34 +55,29 @@ import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; import android.testing.TestableContext; -import android.util.ArrayMap; -import android.util.ArraySet; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import com.android.mediaframeworktest.R; +import com.android.framework.base.media.ringtone.tests.R; +import com.android.media.testing.RingtoneInjectablesTrackingTestRule; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.Description; import org.junit.runner.RunWith; -import org.junit.runners.model.Statement; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.FileNotFoundException; -import java.util.ArrayDeque; -import java.util.Map; -import java.util.Queue; +/** + * Test behavior of {@link Ringtone} when it's created via {@link Ringtone.Builder}. + */ @RunWith(AndroidJUnit4.class) -public class RingtoneTest { +public class RingtoneBuilderTest { private static final Uri SOUND_URI = Uri.parse("content://fake-sound-uri"); @@ -93,11 +90,8 @@ public class RingtoneTest { private static final VibrationEffect VIBRATION_EFFECT = VibrationEffect.createWaveform(new long[] { 0, 100, 50, 100}, -1); - private static final VibrationEffect VIBRATION_EFFECT_REPEATING = - VibrationEffect.createWaveform(new long[] { 0, 100, 50, 100, 50}, 1); - @Rule - public final RingtoneInjectablesTrackingTestRule + @Rule public final RingtoneInjectablesTrackingTestRule mMediaPlayerRule = new RingtoneInjectablesTrackingTestRule(); @Captor private ArgumentCaptor<IBinder> mIBinderCaptor; @@ -122,6 +116,7 @@ public class RingtoneTest { mContext = spy(testContext); } + @Test public void testRingtone_fullLifecycleUsingLocalMediaPlayer() throws Exception { MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer(); @@ -142,14 +137,14 @@ public class RingtoneTest { assertThat(ringtone.isLocalOnly()).isFalse(); // Prepare - verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES); + verifyPlayerSetup(mContext, mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES); verify(mockMediaPlayer).setVolume(1.0f); verify(mockMediaPlayer).setLooping(false); verify(mockMediaPlayer).prepare(); // Play ringtone.play(); - verifyLocalPlay(mockMediaPlayer); + verifyPlayerStarted(mockMediaPlayer); // Verify dynamic controls. ringtone.setVolume(0.8f); @@ -165,7 +160,7 @@ public class RingtoneTest { // Release ringtone.stop(); - verifyLocalStop(mockMediaPlayer); + verifyPlayerStopped(mockMediaPlayer); // This test is intended to strictly verify all interactions with MediaPlayer in a local // playback case. This shouldn't be necessary in other tests that have the same basic @@ -199,16 +194,16 @@ public class RingtoneTest { assertThat(ringtone.getAudioAttributes()).isEqualTo(audioAttributes); // Prepare - verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, audioAttributes); + verifyPlayerSetup(mContext, mockMediaPlayer, SOUND_URI, audioAttributes); verify(mockMediaPlayer).prepare(); // Play ringtone.play(); - verifyLocalPlay(mockMediaPlayer); + verifyPlayerStarted(mockMediaPlayer); // Release ringtone.stop(); - verifyLocalStop(mockMediaPlayer); + verifyPlayerStopped(mockMediaPlayer); verifyZeroInteractions(mMockRemotePlayer); verifyZeroInteractions(mMockVibrator); @@ -220,8 +215,8 @@ public class RingtoneTest { setupFileNotFound(mockMediaPlayer, SOUND_URI); Ringtone ringtone = newBuilder(MEDIA_SOUND, RINGTONE_ATTRIBUTES) - .setUri(SOUND_URI) - .build(); + .setUri(SOUND_URI) + .build(); assertThat(ringtone).isNotNull(); assertThat(ringtone.isUsingRemotePlayer()).isTrue(); @@ -284,7 +279,7 @@ public class RingtoneTest { // Prepare // Uses attributes with haptic channels enabled, but will use the effect when there aren't // any present. - verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); + verifyPlayerSetup(mContext, mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); verify(mockMediaPlayer).setVolume(1.0f); verify(mockMediaPlayer).setLooping(false); verify(mockMediaPlayer).prepare(); @@ -292,7 +287,7 @@ public class RingtoneTest { // Play ringtone.play(); - verifyLocalPlay(mockMediaPlayer); + verifyPlayerStarted(mockMediaPlayer); verify(mMockVibrator).vibrate(VIBRATION_EFFECT, RINGTONE_VIB_ATTRIBUTES); // Verify dynamic controls. @@ -310,7 +305,7 @@ public class RingtoneTest { // Release ringtone.stop(); - verifyLocalStop(mockMediaPlayer); + verifyPlayerStopped(mockMediaPlayer); verify(mMockVibrator).cancel(VibrationAttributes.USAGE_RINGTONE); // This test is intended to strictly verify all interactions with MediaPlayer in a local @@ -388,7 +383,7 @@ public class RingtoneTest { // Prepare // Uses attributes with haptic channels enabled, but will abandon the MediaPlayer when it // knows there aren't any. - verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); + verifyPlayerSetup(mContext, mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); verify(mockMediaPlayer).setVolume(0.0f); // Vibration-only: sound muted. verify(mockMediaPlayer).setLooping(false); verify(mockMediaPlayer).prepare(); @@ -443,7 +438,7 @@ public class RingtoneTest { // Prepare // Uses attributes with haptic channels enabled, but will use the effect when there aren't // any present. - verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); + verifyPlayerSetup(mContext, mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); verify(mockMediaPlayer).setVolume(0.0f); // Vibration-only: sound muted. verify(mockMediaPlayer).setLooping(false); verify(mockMediaPlayer).prepare(); @@ -451,7 +446,7 @@ public class RingtoneTest { // Play ringtone.play(); // Vibrator.vibrate isn't called because the vibration comes from the sound. - verifyLocalPlay(mockMediaPlayer); + verifyPlayerStarted(mockMediaPlayer); // Verify dynamic controls (no-op without sound) ringtone.setVolume(0.8f); @@ -466,7 +461,7 @@ public class RingtoneTest { // Release ringtone.stop(); - verifyLocalStop(mockMediaPlayer); + verifyPlayerStopped(mockMediaPlayer); // This test is intended to strictly verify all interactions with MediaPlayer in a local // playback case. This shouldn't be necessary in other tests that have the same basic @@ -496,17 +491,17 @@ public class RingtoneTest { // Prepare // The attributes here have haptic channels enabled (unlike above) - verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); + verifyPlayerSetup(mContext, mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); verify(mockMediaPlayer).prepare(); // Play ringtone.play(); when(mockMediaPlayer.isPlaying()).thenReturn(true); - verifyLocalPlay(mockMediaPlayer); + verifyPlayerStarted(mockMediaPlayer); // Release ringtone.stop(); - verifyLocalStop(mockMediaPlayer); + verifyPlayerStopped(mockMediaPlayer); verifyZeroInteractions(mMockRemotePlayer); // Nothing after the initial hasVibrator - it uses audio-coupled. @@ -536,7 +531,7 @@ public class RingtoneTest { // Prepare // The attributes here have haptic channels enabled (unlike above) - verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); + verifyPlayerSetup(mContext, mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC); verify(mockMediaPlayer).prepare(); // Play @@ -559,7 +554,7 @@ public class RingtoneTest { @Test public void testRingtone_nullMediaOnBuilderUsesFallback() throws Exception { AssetFileDescriptor testResourceFd = - mContext.getResources().openRawResourceFd(R.raw.shortmp3); + mContext.getResources().openRawResourceFd(R.raw.test_sound_file); // Ensure it will flow as expected. assertThat(testResourceFd).isNotNull(); assertThat(testResourceFd.getDeclaredLength()).isAtLeast(0); @@ -575,18 +570,18 @@ public class RingtoneTest { // Delegates straight to fallback in local player. // Prepare - verifyLocalPlayerFallbackSetup(mockMediaPlayer, testResourceFd, RINGTONE_ATTRIBUTES); + verifyPlayerFallbackSetup(mockMediaPlayer, testResourceFd, RINGTONE_ATTRIBUTES); verify(mockMediaPlayer).setVolume(1.0f); verify(mockMediaPlayer).setLooping(false); verify(mockMediaPlayer).prepare(); // Play ringtone.play(); - verifyLocalPlay(mockMediaPlayer); + verifyPlayerStarted(mockMediaPlayer); // Release ringtone.stop(); - verifyLocalStop(mockMediaPlayer); + verifyPlayerStopped(mockMediaPlayer); verifyNoMoreInteractions(mockMediaPlayer); verifyNoMoreInteractions(mMockRemotePlayer); @@ -615,24 +610,10 @@ public class RingtoneTest { verifyNoMoreInteractions(mMockRemotePlayer); } - @Test - public void testRingtone_noMediaSetOnBuilderFallbackFailsAndNoRemote() throws Exception { - mContext.getOrCreateTestableResources() - .addOverride(com.android.internal.R.raw.fallbackring, null); - Ringtone ringtone = newBuilder(MEDIA_SOUND, RINGTONE_ATTRIBUTES) - .setUri(null) - .setLocalOnly() - .build(); - // Local player fallback fails as the resource isn't found (no media player creation is - // attempted), and since there is no local player, the ringtone ends up having nothing to - // do. - assertThat(ringtone).isNull(); - } - private Ringtone.Builder newBuilder(@Ringtone.RingtoneMedia int ringtoneMedia, AudioAttributes audioAttributes) { return new Ringtone.Builder(mContext, ringtoneMedia, audioAttributes) - .setInjectables(mMediaPlayerRule.injectables); + .setInjectables(mMediaPlayerRule.getRingtoneTestInjectables()); } private static AudioAttributes audioAttributes(int audioUsage) { @@ -647,194 +628,4 @@ public class RingtoneTest { doThrow(new FileNotFoundException("Fake file not found")) .when(mockMediaPlayer).setDataSource(any(Context.class), eq(uri)); } - - private void verifyLocalPlayerSetup(MediaPlayer mockPlayer, Uri expectedUri, - AudioAttributes expectedAudioAttributes) throws Exception { - verify(mockPlayer).setDataSource(mContext, expectedUri); - verify(mockPlayer).setAudioAttributes(expectedAudioAttributes); - verify(mockPlayer).setPreferredDevice(null); - verify(mockPlayer).prepare(); - } - - private void verifyLocalPlayerFallbackSetup(MediaPlayer mockPlayer, AssetFileDescriptor afd, - AudioAttributes expectedAudioAttributes) throws Exception { - // This is very specific but it's a simple way to test that the test resource matches. - if (afd.getDeclaredLength() < 0) { - verify(mockPlayer).setDataSource(afd.getFileDescriptor()); - } else { - verify(mockPlayer).setDataSource(afd.getFileDescriptor(), - afd.getStartOffset(), - afd.getDeclaredLength()); - } - verify(mockPlayer).setAudioAttributes(expectedAudioAttributes); - verify(mockPlayer).setPreferredDevice(null); - verify(mockPlayer).prepare(); - } - - private void verifyLocalPlay(MediaPlayer mockMediaPlayer) { - verify(mockMediaPlayer).setOnCompletionListener(any()); - verify(mockMediaPlayer).start(); - } - - private void verifyLocalStop(MediaPlayer mockMediaPlayer) { - verify(mockMediaPlayer).stop(); - verify(mockMediaPlayer).setOnCompletionListener(isNull()); - verify(mockMediaPlayer).reset(); - verify(mockMediaPlayer).release(); - } - - /** - * This rule ensures that all expected media player creations from the factory do actually - * occur. The reason for this level of control is that creating a media player is fairly - * expensive and blocking, so we do want unit tests of this class to "declare" interactions - * of all created media players. - * - * This needs to be a TestRule so that the teardown assertions can be skipped if the test has - * failed (and media player assertions may just be a distracting side effect). Otherwise, the - * teardown failures hide the real test ones. - */ - public static class RingtoneInjectablesTrackingTestRule implements TestRule { - public Ringtone.Injectables injectables = new TestInjectables(); - public boolean hapticGeneratorAvailable = true; - - // Queue of (local) media players, in order of expected creation. Enqueue using - // expectNewMediaPlayer(), dequeued by the media player factory passed to Ringtone. - // This queue is asserted to be empty at the end of the test. - private Queue<MediaPlayer> mMockMediaPlayerQueue = new ArrayDeque<>(); - - // Similar to media players, but for haptic generator, which also needs releasing. - private Map<MediaPlayer, HapticGenerator> mMockHapticGeneratorMap = new ArrayMap<>(); - - // Media players with haptic channels. - private ArraySet<MediaPlayer> mHapticChannels = new ArraySet<>(); - - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - base.evaluate(); - // Only assert if the test didn't fail (base.evaluate() would throw). - assertWithMessage("Test setup an expectLocalMediaPlayer but it wasn't consumed") - .that(mMockMediaPlayerQueue).isEmpty(); - // Only assert if the test didn't fail (base.evaluate() would throw). - assertWithMessage( - "Test setup an expectLocalHapticGenerator but it wasn't consumed") - .that(mMockHapticGeneratorMap).isEmpty(); - } - }; - } - - private TestMediaPlayer expectLocalMediaPlayer() { - TestMediaPlayer mockMediaPlayer = Mockito.mock(TestMediaPlayer.class); - // Delegate to simulated methods. This means they can be verified but also reflect - // realistic transitions from the TestMediaPlayer. - doCallRealMethod().when(mockMediaPlayer).start(); - doCallRealMethod().when(mockMediaPlayer).stop(); - doCallRealMethod().when(mockMediaPlayer).setLooping(anyBoolean()); - when(mockMediaPlayer.isLooping()).thenCallRealMethod(); - when(mockMediaPlayer.isLooping()).thenCallRealMethod(); - mMockMediaPlayerQueue.add(mockMediaPlayer); - return mockMediaPlayer; - } - - private HapticGenerator expectHapticGenerator(MediaPlayer mockMediaPlayer) { - HapticGenerator mockHapticGenerator = Mockito.mock(HapticGenerator.class); - // A test should never want this. - assertWithMessage("Can't expect a second haptic generator created " - + "for one media player") - .that(mMockHapticGeneratorMap.put(mockMediaPlayer, mockHapticGenerator)) - .isNull(); - return mockHapticGenerator; - } - - private void setHasHapticChannels(MediaPlayer mp, boolean hasHapticChannels) { - if (hasHapticChannels) { - mHapticChannels.add(mp); - } else { - mHapticChannels.remove(mp); - } - } - - private class TestInjectables extends Ringtone.Injectables { - @Override - public MediaPlayer newMediaPlayer() { - assertWithMessage( - "Unexpected MediaPlayer creation. Bug or need expectNewMediaPlayer") - .that(mMockMediaPlayerQueue) - .isNotEmpty(); - return mMockMediaPlayerQueue.remove(); - } - - @Override - public boolean isHapticGeneratorAvailable() { - return hapticGeneratorAvailable; - } - - @Override - public HapticGenerator createHapticGenerator(MediaPlayer mediaPlayer) { - HapticGenerator mockHapticGenerator = mMockHapticGeneratorMap.remove(mediaPlayer); - assertWithMessage("Unexpected HapticGenerator creation. " - + "Bug or need expectHapticGenerator") - .that(mockHapticGenerator) - .isNotNull(); - return mockHapticGenerator; - } - - @Override - public boolean isHapticPlaybackSupported() { - return true; - } - - @Override - public boolean hasHapticChannels(MediaPlayer mp) { - return mHapticChannels.contains(mp); - } - } - } - - /** - * MediaPlayer relies on a native backend and so its necessary to intercept calls from - * fake usage hitting them. - * - * Mocks don't work directly on native calls, but if they're overridden then it does work. - * Some basic state faking is also done to make the mocks more realistic. - */ - private static class TestMediaPlayer extends MediaPlayer { - private boolean mIsPlaying = false; - private boolean mIsLooping = false; - - @Override - public void start() { - mIsPlaying = true; - } - - @Override - public void stop() { - mIsPlaying = false; - } - - @Override - public void setLooping(boolean value) { - mIsLooping = value; - } - - @Override - public boolean isLooping() { - return mIsLooping; - } - - @Override - public boolean isPlaying() { - return mIsPlaying; - } - - void simulatePlayingFinished() { - if (!mIsPlaying) { - throw new IllegalStateException( - "Attempted to pretend playing finished when not playing"); - } - mIsPlaying = false; - } - } } diff --git a/media/tests/ringtone/src/com/android/media/testing/MediaPlayerTestHelper.java b/media/tests/ringtone/src/com/android/media/testing/MediaPlayerTestHelper.java new file mode 100644 index 000000000000..e97e1173a1ea --- /dev/null +++ b/media/tests/ringtone/src/com/android/media/testing/MediaPlayerTestHelper.java @@ -0,0 +1,75 @@ +/* + * Copyright 2023 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.media.testing; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.media.AudioAttributes; +import android.media.MediaPlayer; +import android.net.Uri; + +/** + * Helper class with assertion methods on mock {@link MediaPlayer} instances. + */ +public final class MediaPlayerTestHelper { + + /** Verify this local media player mock instance was started. */ + public static void verifyPlayerStarted(MediaPlayer mockMediaPlayer) { + verify(mockMediaPlayer).setOnCompletionListener(any()); + verify(mockMediaPlayer).start(); + } + + /** Verify this local media player mock instance was stopped and released. */ + public static void verifyPlayerStopped(MediaPlayer mockMediaPlayer) { + verify(mockMediaPlayer).stop(); + verify(mockMediaPlayer).setOnCompletionListener(isNull()); + verify(mockMediaPlayer).reset(); + verify(mockMediaPlayer).release(); + } + + /** Verify this local media player mock instance was setup with given attributes. */ + public static void verifyPlayerSetup(Context context, MediaPlayer mockPlayer, + Uri expectedUri, AudioAttributes expectedAudioAttributes) throws Exception { + verify(mockPlayer).setDataSource(context, expectedUri); + verify(mockPlayer).setAudioAttributes(expectedAudioAttributes); + verify(mockPlayer).setPreferredDevice(null); + verify(mockPlayer).prepare(); + } + + /** Verify this local media player mock instance was setup with given fallback attributes. */ + public static void verifyPlayerFallbackSetup(MediaPlayer mockPlayer, + AssetFileDescriptor afd, AudioAttributes expectedAudioAttributes) throws Exception { + // This is very specific but it's a simple way to test that the test resource matches. + if (afd.getDeclaredLength() < 0) { + verify(mockPlayer).setDataSource(afd.getFileDescriptor()); + } else { + verify(mockPlayer).setDataSource(afd.getFileDescriptor(), + afd.getStartOffset(), + afd.getDeclaredLength()); + } + verify(mockPlayer).setAudioAttributes(expectedAudioAttributes); + verify(mockPlayer).setPreferredDevice(null); + verify(mockPlayer).prepare(); + } + + private MediaPlayerTestHelper() { + } +} diff --git a/media/tests/ringtone/src/com/android/media/testing/RingtoneInjectablesTrackingTestRule.java b/media/tests/ringtone/src/com/android/media/testing/RingtoneInjectablesTrackingTestRule.java new file mode 100644 index 000000000000..25752ce83e5c --- /dev/null +++ b/media/tests/ringtone/src/com/android/media/testing/RingtoneInjectablesTrackingTestRule.java @@ -0,0 +1,225 @@ +/* + * Copyright 2023 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.media.testing; + +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.when; + +import android.media.MediaPlayer; +import android.media.Ringtone; +import android.media.audiofx.HapticGenerator; +import android.util.ArrayMap; +import android.util.ArraySet; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.mockito.Mockito; + +import java.util.ArrayDeque; +import java.util.Map; +import java.util.Queue; + +/** + * This rule ensures that all expected media player creations from the factory do actually + * occur. The reason for this level of control is that creating a media player is fairly + * expensive and blocking, so we do want unit tests of this class to "declare" interactions + * of all created media players. + * <p> + * This needs to be a TestRule so that the teardown assertions can be skipped if the test has + * failed (and media player assertions may just be a distracting side effect). Otherwise, the + * teardown failures hide the real test ones. + */ +public class RingtoneInjectablesTrackingTestRule implements TestRule { + + private final Ringtone.Injectables mRingtoneTestInjectables = new TestInjectables(); + + // Queue of (local) media players, in order of expected creation. Enqueue using + // expectNewMediaPlayer(), dequeued by the media player factory passed to Ringtone. + // This queue is asserted to be empty at the end of the test. + private final Queue<MediaPlayer> mMockMediaPlayerQueue = new ArrayDeque<>(); + + // Similar to media players, but for haptic generator, which also needs releasing. + private final Map<MediaPlayer, HapticGenerator> mMockHapticGeneratorMap = new ArrayMap<>(); + + // Media players with haptic channels. + private final ArraySet<MediaPlayer> mHapticChannels = new ArraySet<>(); + + private boolean mHapticGeneratorAvailable = true; + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + base.evaluate(); + // Only assert if the test didn't fail (base.evaluate() would throw). + assertWithMessage("Test setup an expectLocalMediaPlayer but it wasn't consumed") + .that(mMockMediaPlayerQueue).isEmpty(); + // Only assert if the test didn't fail (base.evaluate() would throw). + assertWithMessage( + "Test setup an expectLocalHapticGenerator but it wasn't consumed") + .that(mMockHapticGeneratorMap).isEmpty(); + } + }; + } + + /** The {@link Ringtone.Injectables} to be used for creating a testable {@link Ringtone}. */ + public Ringtone.Injectables getRingtoneTestInjectables() { + return mRingtoneTestInjectables; + } + + /** + * Create a test {@link MediaPlayer} that will be provided to the {@link Ringtone} instance + * created with {@link #getRingtoneTestInjectables()}. + * + * <p>If a media player is not created during the test execution after this method is called + * then the test will fail. It will also fail if the ringtone attempts to create one without + * this method being called first. + */ + public TestMediaPlayer expectLocalMediaPlayer() { + TestMediaPlayer mockMediaPlayer = Mockito.mock(TestMediaPlayer.class); + // Delegate to simulated methods. This means they can be verified but also reflect + // realistic transitions from the TestMediaPlayer. + doCallRealMethod().when(mockMediaPlayer).start(); + doCallRealMethod().when(mockMediaPlayer).stop(); + doCallRealMethod().when(mockMediaPlayer).setLooping(anyBoolean()); + when(mockMediaPlayer.isLooping()).thenCallRealMethod(); + mMockMediaPlayerQueue.add(mockMediaPlayer); + return mockMediaPlayer; + } + + /** + * Create a test {@link HapticGenerator} that will be provided to the {@link Ringtone} instance + * created with {@link #getRingtoneTestInjectables()}. + * + * <p>If a haptic generator is not created during the test execution after this method is called + * then the test will fail. It will also fail if the ringtone attempts to create one without + * this method being called first. + */ + public HapticGenerator expectHapticGenerator(MediaPlayer mediaPlayer) { + HapticGenerator mockHapticGenerator = Mockito.mock(HapticGenerator.class); + // A test should never want this. + assertWithMessage("Can't expect a second haptic generator created " + + "for one media player") + .that(mMockHapticGeneratorMap.put(mediaPlayer, mockHapticGenerator)) + .isNull(); + return mockHapticGenerator; + } + + /** + * Configures the {@link MediaPlayer} to always return given flag when + * {@link Ringtone.Injectables#hasHapticChannels(MediaPlayer)} is called. + */ + public void setHasHapticChannels(MediaPlayer mp, boolean hasHapticChannels) { + if (hasHapticChannels) { + mHapticChannels.add(mp); + } else { + mHapticChannels.remove(mp); + } + } + + /** Test implementation of {@link Ringtone.Injectables} that uses the test rule setup. */ + private class TestInjectables extends Ringtone.Injectables { + @Override + public MediaPlayer newMediaPlayer() { + assertWithMessage( + "Unexpected MediaPlayer creation. Bug or need expectNewMediaPlayer") + .that(mMockMediaPlayerQueue) + .isNotEmpty(); + return mMockMediaPlayerQueue.remove(); + } + + @Override + public boolean isHapticGeneratorAvailable() { + return mHapticGeneratorAvailable; + } + + @Override + public HapticGenerator createHapticGenerator(MediaPlayer mediaPlayer) { + HapticGenerator mockHapticGenerator = mMockHapticGeneratorMap.remove(mediaPlayer); + assertWithMessage("Unexpected HapticGenerator creation. " + + "Bug or need expectHapticGenerator") + .that(mockHapticGenerator) + .isNotNull(); + return mockHapticGenerator; + } + + @Override + public boolean isHapticPlaybackSupported() { + return true; + } + + @Override + public boolean hasHapticChannels(MediaPlayer mp) { + return mHapticChannels.contains(mp); + } + } + + /** + * MediaPlayer relies on a native backend and so its necessary to intercept calls from + * fake usage hitting them. + * <p> + * Mocks don't work directly on native calls, but if they're overridden then it does work. + * Some basic state faking is also done to make the mocks more realistic. + */ + public static class TestMediaPlayer extends MediaPlayer { + private boolean mIsPlaying = false; + private boolean mIsLooping = false; + + @Override + public void start() { + mIsPlaying = true; + } + + @Override + public void stop() { + mIsPlaying = false; + } + + @Override + public void setLooping(boolean value) { + mIsLooping = value; + } + + @Override + public boolean isLooping() { + return mIsLooping; + } + + @Override + public boolean isPlaying() { + return mIsPlaying; + } + + /** + * Updates {@link #isPlaying()} result to false, if it's set to true. + * + * @throws IllegalStateException is {@link #isPlaying()} is already false + */ + public void simulatePlayingFinished() { + if (!mIsPlaying) { + throw new IllegalStateException( + "Attempted to pretend playing finished when not playing"); + } + mIsPlaying = false; + } + } +} diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7e44adf84137..7a6d29ab3c1f 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -209,6 +209,8 @@ <string name="screenshot_saved_title">Screenshot saved</string> <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] --> <string name="screenshot_failed_title">Couldn\'t save screenshot</string> + <!-- Appended to the notification content when a screenshot failure happens on an external display. [CHAR LIMIT=50] --> + <string name="screenshot_failed_external_display_indication">External Display</string> <!-- Notification text displayed when we fail to save a screenshot due to locked storage. [CHAR LIMIT=100] --> <string name="screenshot_failed_to_save_user_locked_text">Device must be unlocked before screenshot can be saved</string> <!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] --> diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index b7c3662baa33..4764f223d121 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -626,7 +626,7 @@ object Flags { /** TODO(b/295143676): Tracking bug. When enable, captures a screenshot for each display. */ @JvmField - val MULTI_DISPLAY_SCREENSHOT = unreleasedFlag("multi_display_screenshot") + val MULTI_DISPLAY_SCREENSHOT = unreleasedFlag("multi_display_screenshot", teamfood = true) // 1400 - columbus // TODO(b/254512756): Tracking Bug diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt index 51540673b9e2..c34fd42e2154 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt @@ -20,11 +20,10 @@ import android.util.Log import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.flags.FeatureFlags -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch import java.util.function.Consumer import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch /** Processes a screenshot request sent from [ScreenshotHelper]. */ interface ScreenshotRequestProcessor { @@ -36,16 +35,15 @@ interface ScreenshotRequestProcessor { suspend fun process(screenshot: ScreenshotData): ScreenshotData } -/** - * Implementation of [ScreenshotRequestProcessor] - */ +/** Implementation of [ScreenshotRequestProcessor] */ @SysUISingleton -class RequestProcessor @Inject constructor( - private val capture: ImageCapture, - private val policy: ScreenshotPolicy, - private val flags: FeatureFlags, - /** For the Java Async version, to invoke the callback. */ - @Application private val mainScope: CoroutineScope +class RequestProcessor +@Inject +constructor( + private val capture: ImageCapture, + private val policy: ScreenshotPolicy, + /** For the Java Async version, to invoke the callback. */ + @Application private val mainScope: CoroutineScope ) : ScreenshotRequestProcessor { override suspend fun process(screenshot: ScreenshotData): ScreenshotData { @@ -67,8 +65,9 @@ class RequestProcessor @Inject constructor( result.userHandle = info.user if (policy.isManagedProfile(info.user.identifier)) { - val image = capture.captureTask(info.taskId) - ?: error("Task snapshot returned a null Bitmap!") + val image = + capture.captureTask(info.taskId) + ?: throw RequestProcessorException("Task snapshot returned a null Bitmap!") // Provide the task snapshot as the screenshot result.type = TAKE_SCREENSHOT_PROVIDED_IMAGE @@ -97,3 +96,6 @@ class RequestProcessor @Inject constructor( } private const val TAG = "RequestProcessor" + +/** Exception thrown by [RequestProcessor] if something goes wrong. */ +class RequestProcessorException(message: String) : IllegalStateException(message) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 127a57e26a30..21a08a9a4980 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -325,7 +325,7 @@ public class ScreenshotController { Context context, FeatureFlags flags, ScreenshotSmartActions screenshotSmartActions, - ScreenshotNotificationsController screenshotNotificationsController, + ScreenshotNotificationsController.Factory screenshotNotificationsControllerFactory, ScrollCaptureClient scrollCaptureClient, UiEventLogger uiEventLogger, ImageExporter imageExporter, @@ -346,7 +346,7 @@ public class ScreenshotController { @Assisted boolean showUIOnExternalDisplay ) { mScreenshotSmartActions = screenshotSmartActions; - mNotificationsController = screenshotNotificationsController; + mNotificationsController = screenshotNotificationsControllerFactory.create(displayId); mScrollCaptureClient = scrollCaptureClient; mUiEventLogger = uiEventLogger; mImageExporter = imageExporter; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java deleted file mode 100644 index 4344fd1a7567..000000000000 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.systemui.screenshot; - -import static android.content.Context.NOTIFICATION_SERVICE; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.os.UserHandle; -import android.util.DisplayMetrics; -import android.view.WindowManager; - -import com.android.internal.messages.nano.SystemMessageProto; -import com.android.systemui.res.R; -import com.android.systemui.SystemUIApplication; -import com.android.systemui.util.NotificationChannels; - -import javax.inject.Inject; - -/** - * Convenience class to handle showing and hiding notifications while taking a screenshot. - */ -public class ScreenshotNotificationsController { - private static final String TAG = "ScreenshotNotificationManager"; - - private final Context mContext; - private final Resources mResources; - private final NotificationManager mNotificationManager; - - @Inject - ScreenshotNotificationsController(Context context, WindowManager windowManager) { - mContext = context; - mResources = context.getResources(); - mNotificationManager = - (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - - DisplayMetrics displayMetrics = new DisplayMetrics(); - windowManager.getDefaultDisplay().getRealMetrics(displayMetrics); - } - - /** - * Sends a notification that the screenshot capture has failed. - */ - public void notifyScreenshotError(int msgResId) { - Resources res = mContext.getResources(); - String errorMsg = res.getString(msgResId); - - // Repurpose the existing notification to notify the user of the error - Notification.Builder b = new Notification.Builder(mContext, NotificationChannels.ALERTS) - .setTicker(res.getString(R.string.screenshot_failed_title)) - .setContentTitle(res.getString(R.string.screenshot_failed_title)) - .setContentText(errorMsg) - .setSmallIcon(R.drawable.stat_notify_image_error) - .setWhen(System.currentTimeMillis()) - .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen - .setCategory(Notification.CATEGORY_ERROR) - .setAutoCancel(true) - .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)); - final DevicePolicyManager dpm = - (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - final Intent intent = - dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); - if (intent != null) { - final PendingIntent pendingIntent = PendingIntent.getActivityAsUser( - mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT); - b.setContentIntent(pendingIntent); - } - - SystemUIApplication.overrideNotificationAppName(mContext, b, true); - - Notification n = new Notification.BigTextStyle(b) - .bigText(errorMsg) - .build(); - mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT, n); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.kt new file mode 100644 index 000000000000..d874eb68460b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2023 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.systemui.screenshot + +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.admin.DevicePolicyManager +import android.content.Context +import android.os.UserHandle +import android.view.Display +import com.android.internal.R +import com.android.internal.messages.nano.SystemMessageProto +import com.android.systemui.SystemUIApplication +import com.android.systemui.util.NotificationChannels +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +/** Convenience class to handle showing and hiding notifications while taking a screenshot. */ +class ScreenshotNotificationsController +@AssistedInject +internal constructor( + @Assisted private val displayId: Int, + private val context: Context, + private val notificationManager: NotificationManager, + private val devicePolicyManager: DevicePolicyManager, +) { + private val res = context.resources + + /** + * Sends a notification that the screenshot capture has failed. + * + * Errors for the non-default display are shown in a unique separate notification. + */ + fun notifyScreenshotError(msgResId: Int) { + val displayErrorString = + if (displayId != Display.DEFAULT_DISPLAY) { + " ($externalDisplayString)" + } else { + "" + } + val errorMsg = res.getString(msgResId) + displayErrorString + + // Repurpose the existing notification or create a new one + val builder = + Notification.Builder(context, NotificationChannels.ALERTS) + .setTicker(res.getString(com.android.systemui.res.R.string.screenshot_failed_title)) + .setContentTitle( + res.getString(com.android.systemui.res.R.string.screenshot_failed_title) + ) + .setContentText(errorMsg) + .setSmallIcon(com.android.systemui.res.R.drawable.stat_notify_image_error) + .setWhen(System.currentTimeMillis()) + .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen + .setCategory(Notification.CATEGORY_ERROR) + .setAutoCancel(true) + .setColor(context.getColor(R.color.system_notification_accent_color)) + val intent = + devicePolicyManager.createAdminSupportIntent( + DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE + ) + if (intent != null) { + val pendingIntent = + PendingIntent.getActivityAsUser( + context, + 0, + intent, + PendingIntent.FLAG_IMMUTABLE, + null, + UserHandle.CURRENT + ) + builder.setContentIntent(pendingIntent) + } + SystemUIApplication.overrideNotificationAppName(context, builder, true) + val notification = Notification.BigTextStyle(builder).bigText(errorMsg).build() + // A different id for external displays to keep the 2 error notifications separated. + val id = + if (displayId == Display.DEFAULT_DISPLAY) { + SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT + } else { + SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT_EXTERNAL_DISPLAY + } + notificationManager.notify(id, notification) + } + + private val externalDisplayString: String + get() = + res.getString( + com.android.systemui.res.R.string.screenshot_failed_external_display_indication + ) + + /** Factory for [ScreenshotNotificationsController]. */ + @AssistedFactory + interface Factory { + fun create(displayId: Int = Display.DEFAULT_DISPLAY): ScreenshotNotificationsController + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotServiceErrorReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotServiceErrorReceiver.java index 070fb1eef99a..049799e96c53 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotServiceErrorReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotServiceErrorReceiver.java @@ -16,25 +16,29 @@ package com.android.systemui.screenshot; +import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.view.WindowManager; +import android.view.Display; import com.android.systemui.res.R; /** - * Performs a number of miscellaneous, non-system-critical actions - * after the system has finished booting. + * Receives errors related to screenshot. */ public class ScreenshotServiceErrorReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { // Show a message that we've failed to save the image to disk - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - ScreenshotNotificationsController controller = - new ScreenshotNotificationsController(context, wm); + NotificationManager notificationManager = context.getSystemService( + NotificationManager.class); + DevicePolicyManager devicePolicyManager = context.getSystemService( + DevicePolicyManager.class); + ScreenshotNotificationsController controller = new ScreenshotNotificationsController( + Display.DEFAULT_DISPLAY, context, notificationManager, devicePolicyManager); controller.notifyScreenshotError(R.string.screenshot_failed_to_save_unknown_text); } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt index abe40ff11ead..015828438375 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt @@ -10,6 +10,8 @@ import com.android.internal.util.ScreenshotRequest import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.display.data.repository.DisplayRepository +import com.android.systemui.res.R +import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback import java.util.function.Consumer import javax.inject.Inject @@ -34,7 +36,8 @@ constructor( displayRepository: DisplayRepository, @Application private val mainScope: CoroutineScope, private val screenshotRequestProcessor: ScreenshotRequestProcessor, - private val uiEventLogger: UiEventLogger + private val uiEventLogger: UiEventLogger, + private val screenshotNotificationControllerFactory: ScreenshotNotificationsController.Factory, ) { private lateinit var displays: StateFlow<Set<Display>> @@ -44,6 +47,7 @@ constructor( } private val screenshotControllers = mutableMapOf<Int, ScreenshotController>() + private val notificationControllers = mutableMapOf<Int, ScreenshotNotificationsController>() /** * Executes the [ScreenshotRequest]. @@ -58,40 +62,68 @@ constructor( ) { val displayIds = getDisplaysToScreenshot(screenshotRequest.type) val resultCallbackWrapper = MultiResultCallbackWrapper(requestCallback) - screenshotRequest.oneForEachDisplay(displayIds).forEach { screenshotData: ScreenshotData -> + displayIds.forEach { displayId: Int -> dispatchToController( - screenshotData = screenshotData, + rawScreenshotData = ScreenshotData.fromRequest(screenshotRequest, displayId), onSaved = - if (screenshotData.displayId == Display.DEFAULT_DISPLAY) onSaved else { _ -> }, - callback = resultCallbackWrapper.createCallbackForId(screenshotData.displayId) + if (displayId == Display.DEFAULT_DISPLAY) { + onSaved + } else { _ -> }, + callback = resultCallbackWrapper.createCallbackForId(displayId) ) } } - /** Creates a [ScreenshotData] for each display. */ - private suspend fun ScreenshotRequest.oneForEachDisplay( - displayIds: List<Int> - ): List<ScreenshotData> { - return displayIds - .map { displayId -> ScreenshotData.fromRequest(this, displayId) } - .map { screenshotData: ScreenshotData -> - screenshotRequestProcessor.process(screenshotData) - } - } - - private fun dispatchToController( - screenshotData: ScreenshotData, + /** All logging should be triggered only by this method. */ + private suspend fun dispatchToController( + rawScreenshotData: ScreenshotData, onSaved: (Uri) -> Unit, callback: RequestCallback ) { + // Let's wait before logging "screenshot requested", as we should log the processed + // ScreenshotData. + val screenshotData = + try { + screenshotRequestProcessor.process(rawScreenshotData) + } catch (e: RequestProcessorException) { + Log.e(TAG, "Failed to process screenshot request!", e) + logScreenshotRequested(rawScreenshotData) + onFailedScreenshotRequest(rawScreenshotData, callback) + return + } + + logScreenshotRequested(screenshotData) + Log.d(TAG, "Screenshot request: $screenshotData") + try { + getScreenshotController(screenshotData.displayId) + .handleScreenshot(screenshotData, onSaved, callback) + } catch (e: IllegalStateException) { + Log.e(TAG, "Error while ScreenshotController was handling ScreenshotData!", e) + onFailedScreenshotRequest(screenshotData, callback) + return // After a failure log, nothing else should run. + } + } + + /** + * This should be logged also in case of failed requests, before the [SCREENSHOT_CAPTURE_FAILED] + * event. + */ + private fun logScreenshotRequested(screenshotData: ScreenshotData) { uiEventLogger.log( ScreenshotEvent.getScreenshotSource(screenshotData.source), 0, screenshotData.packageNameString ) - Log.d(TAG, "Screenshot request: $screenshotData") - getScreenshotController(screenshotData.displayId) - .handleScreenshot(screenshotData, onSaved, callback) + } + + private fun onFailedScreenshotRequest( + screenshotData: ScreenshotData, + callback: RequestCallback + ) { + uiEventLogger.log(SCREENSHOT_CAPTURE_FAILED, 0, screenshotData.packageNameString) + getNotificationController(screenshotData.displayId) + .notifyScreenshotError(R.string.screenshot_failed_to_capture_text) + callback.reportError() } private fun getDisplaysToScreenshot(requestType: Int): List<Int> { @@ -140,6 +172,12 @@ constructor( } } + private fun getNotificationController(id: Int): ScreenshotNotificationsController { + return notificationControllers.computeIfAbsent(id) { + screenshotNotificationControllerFactory.create(id) + } + } + /** For java compatibility only. see [executeScreenshots] */ fun executeScreenshotsAsync( screenshotRequest: ScreenshotRequest, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java index 75d52cbe2e36..0991c9a326c8 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java @@ -113,7 +113,8 @@ public class TakeScreenshotService extends Service { @Inject public TakeScreenshotService(ScreenshotController.Factory screenshotControllerFactory, UserManager userManager, DevicePolicyManager devicePolicyManager, - UiEventLogger uiEventLogger, ScreenshotNotificationsController notificationsController, + UiEventLogger uiEventLogger, + ScreenshotNotificationsController.Factory notificationsControllerFactory, Context context, @Background Executor bgExecutor, FeatureFlags featureFlags, RequestProcessor processor, Provider<TakeScreenshotExecutor> takeScreenshotExecutor) { if (DEBUG_SERVICE) { @@ -123,7 +124,7 @@ public class TakeScreenshotService extends Service { mUserManager = userManager; mDevicePolicyManager = devicePolicyManager; mUiEventLogger = uiEventLogger; - mNotificationsController = notificationsController; + mNotificationsController = notificationsControllerFactory.create(Display.DEFAULT_DISPLAY); mContext = context; mBgExecutor = bgExecutor; mFeatureFlags = featureFlags; @@ -246,15 +247,17 @@ public class TakeScreenshotService extends Service { Log.d(TAG, "Processing screenshot data"); - ScreenshotData screenshotData = ScreenshotData.fromRequest( - request, Display.DEFAULT_DISPLAY); + if (mFeatureFlags.isEnabled(MULTI_DISPLAY_SCREENSHOT)) { + mTakeScreenshotExecutor.get().executeScreenshotsAsync(request, onSaved, callback); + return; + } + // TODO(b/295143676): Delete the following after the flag is released. try { - if (mFeatureFlags.isEnabled(MULTI_DISPLAY_SCREENSHOT)) { - mTakeScreenshotExecutor.get().executeScreenshotsAsync(request, onSaved, callback); - } else { - mProcessor.processAsync(screenshotData, (data) -> - dispatchToController(data, onSaved, callback)); - } + ScreenshotData screenshotData = ScreenshotData.fromRequest( + request, Display.DEFAULT_DISPLAY); + mProcessor.processAsync(screenshotData, (data) -> + dispatchToController(data, onSaved, callback)); + } catch (IllegalStateException e) { Log.e(TAG, "Failed to process screenshot request!", e); logFailedRequest(request); @@ -264,6 +267,7 @@ public class TakeScreenshotService extends Service { } } + // TODO(b/295143676): Delete this. private void dispatchToController(ScreenshotData screenshot, Consumer<Uri> uriConsumer, RequestCallback callback) { mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshot.getSource()), 0, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index d4b6dfb9b625..61ebcc0c99d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -15,6 +15,7 @@ */ package com.android.systemui.statusbar; + import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.KeyguardManager; @@ -48,10 +49,10 @@ import androidx.annotation.Nullable; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; -import com.android.systemui.res.R; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.res.R; import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.RemoteInputControllerLogger; @@ -535,7 +536,8 @@ public class NotificationRemoteInputManager implements Dumpable { public void cleanUpRemoteInputForUserRemoval(NotificationEntry entry) { if (isRemoteInputActive(entry)) { entry.mRemoteEditImeVisible = false; - mRemoteInputController.removeRemoteInput(entry, null); + mRemoteInputController.removeRemoteInput(entry, null, + /* reason= */"RemoteInputManager#cleanUpRemoteInputForUserRemoval"); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java index d5e4902366e7..63282d2904e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java @@ -31,6 +31,8 @@ import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.util.DumpUtilsKt; +import com.google.errorprone.annotations.CompileTimeConstant; + import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Objects; @@ -96,7 +98,8 @@ public class RemoteInputController { * the entry is only removed if the token matches the last added token for this * entry. If null, the entry is removed regardless. */ - public void removeRemoteInput(NotificationEntry entry, Object token) { + public void removeRemoteInput(NotificationEntry entry, Object token, + @CompileTimeConstant String reason) { Objects.requireNonNull(entry); if (entry.mRemoteEditImeVisible && entry.mRemoteEditImeAnimatingAway) { mLogger.logRemoveRemoteInput( @@ -104,9 +107,12 @@ public class RemoteInputController { true /* remoteEditImeVisible */, true /* remoteEditImeAnimatingAway */, isRemoteInputActive(entry) /* isRemoteInputActiveForEntry */, - isRemoteInputActive() /* isRemoteInputActive */); + isRemoteInputActive() /* isRemoteInputActive */, + reason /* reason */, + entry.getNotificationStyle()/* notificationStyle */); return; } + // If the view is being removed, this may be called even though we're not active boolean remoteInputActiveForEntry = isRemoteInputActive(entry); mLogger.logRemoveRemoteInput( @@ -114,7 +120,9 @@ public class RemoteInputController { entry.mRemoteEditImeVisible /* remoteEditImeVisible */, entry.mRemoteEditImeAnimatingAway /* remoteEditImeAnimatingAway */, remoteInputActiveForEntry /* isRemoteInputActiveForEntry */, - isRemoteInputActive()/* isRemoteInputActive */); + isRemoteInputActive()/* isRemoteInputActive */, + reason/* reason */, + entry.getNotificationStyle()/* notificationStyle */); if (!remoteInputActiveForEntry) return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt index 39b999cb4f35..97770316442c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt @@ -52,20 +52,25 @@ constructor(@NotificationRemoteInputLog private val logBuffer: LogBuffer) { remoteEditImeVisible: Boolean, remoteEditImeAnimatingAway: Boolean, isRemoteInputActiveForEntry: Boolean, - isRemoteInputActive: Boolean + isRemoteInputActive: Boolean, + reason: String, + notificationStyle: String ) = logBuffer.log( TAG, DEBUG, { str1 = entryKey + str2 = reason + str3 = notificationStyle bool1 = remoteEditImeVisible bool2 = remoteEditImeAnimatingAway bool3 = isRemoteInputActiveForEntry bool4 = isRemoteInputActive }, { - "removeRemoteInput entry: $str1, remoteEditImeVisible: $bool1" + + "removeRemoteInput reason: $str2 entry: $str1" + + ", style: $str3, remoteEditImeVisible: $bool1" + ", remoteEditImeAnimatingAway: $bool2, isRemoteInputActiveForEntry: $bool3" + ", isRemoteInputActive: $bool4" } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index affd2d186774..4573d5989faa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -979,6 +979,19 @@ public final class NotificationEntry extends ListEntry { return mExpandAnimationRunning; } + /** + * @return NotificationStyle + */ + public String getNotificationStyle() { + if (isSummaryWithChildren()) { + return "summary"; + } + + final Class<? extends Notification.Style> style = + getSbn().getNotification().getNotificationStyle(); + return style == null ? "nostyle" : style.getSimpleName(); + } + /** Information about a suggestion that is being edited. */ public static class EditedSuggestionInfo { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 9340b85a743d..11c65e542bcd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -1901,16 +1901,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return traceTag; } - if (isSummaryWithChildren()) { - return traceTag + "(summary)"; - } - Class<? extends Notification.Style> style = - getEntry().getSbn().getNotification().getNotificationStyle(); - if (style == null) { - return traceTag + "(nostyle)"; - } else { - return traceTag + "(" + style.getSimpleName() + ")"; - } + return traceTag + "(" + getEntry().getNotificationStyle() + ")"; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index 53fed3d2438f..7c96029cfe15 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -305,7 +305,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene && editTextRootWindowInsets.isVisible(WindowInsets.Type.ime()); if (!mEntry.mRemoteEditImeVisible && !mEditText.mShowImeOnInputConnection) { // Pass null to ensure all inputs are cleared for this entry b/227115380 - mController.removeRemoteInput(mEntry, null); + mController.removeRemoteInput(mEntry, null, + /* reason= */"RemoteInputView$WindowInsetAnimation#onEnd"); } } } @@ -426,7 +427,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene @VisibleForTesting void onDefocus(boolean animate, boolean logClose, @Nullable Runnable doAfterDefocus) { - mController.removeRemoteInput(mEntry, mToken); + mController.removeRemoteInput(mEntry, mToken, /* reason= */"RemoteInputView#onDefocus"); mEntry.remoteInputText = mEditText.getText(); // During removal, we get reattached and lose focus. Not hiding in that @@ -536,7 +537,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene if (mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) { return; } - mController.removeRemoteInput(mEntry, mToken); + mController.removeRemoteInput(mEntry, mToken, + /* reason= */"RemoteInputView#onDetachedFromWindow"); mController.removeSpinning(mEntry.getKey(), mToken); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt index a50fd6f86e09..6c0d43394074 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt @@ -255,7 +255,8 @@ class RemoteInputViewControllerImpl @Inject constructor( entry.lastRemoteInputSent = SystemClock.elapsedRealtime() entry.mRemoteEditImeAnimatingAway = true remoteInputController.addSpinning(entry.key, view.mToken) - remoteInputController.removeRemoteInput(entry, view.mToken) + remoteInputController.removeRemoteInput(entry, view.mToken, + /* reason= */ "RemoteInputViewController#sendRemoteInput") remoteInputController.remoteInputSent(entry) entry.setHasSentReply() diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt index 0d694ee80def..7e41745936f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt @@ -28,7 +28,6 @@ import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE import com.android.internal.util.ScreenshotRequest -import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -47,7 +46,6 @@ class RequestProcessorTest { private val scope = CoroutineScope(Dispatchers.Unconfined) private val policy = FakeScreenshotPolicy() - private val flags = FakeFeatureFlags() /** Tests the Java-compatible function wrapper, ensures callback is invoked. */ @Test @@ -58,7 +56,7 @@ class RequestProcessorTest { .setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)) .build() ) - val processor = RequestProcessor(imageCapture, policy, flags, scope) + val processor = RequestProcessor(imageCapture, policy, scope) var result: ScreenshotData? = null var callbackCount = 0 @@ -86,7 +84,7 @@ class RequestProcessorTest { val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER).build() - val processor = RequestProcessor(imageCapture, policy, flags, scope) + val processor = RequestProcessor(imageCapture, policy, scope) val processedData = processor.process(ScreenshotData.fromRequest(request)) @@ -111,7 +109,7 @@ class RequestProcessorTest { val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER).build() - val processor = RequestProcessor(imageCapture, policy, flags, scope) + val processor = RequestProcessor(imageCapture, policy, scope) val processedData = processor.process(ScreenshotData.fromRequest(request)) @@ -138,7 +136,7 @@ class RequestProcessorTest { val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER).build() - val processor = RequestProcessor(imageCapture, policy, flags, scope) + val processor = RequestProcessor(imageCapture, policy, scope) Assert.assertThrows(IllegalStateException::class.java) { runBlocking { processor.process(ScreenshotData.fromRequest(request)) } @@ -148,7 +146,7 @@ class RequestProcessorTest { @Test fun testProvidedImageScreenshot() = runBlocking { val bounds = Rect(50, 50, 150, 150) - val processor = RequestProcessor(imageCapture, policy, flags, scope) + val processor = RequestProcessor(imageCapture, policy, scope) policy.setManagedProfile(USER_ID, false) @@ -173,7 +171,7 @@ class RequestProcessorTest { @Test fun testProvidedImageScreenshot_managedProfile() = runBlocking { val bounds = Rect(50, 50, 150, 150) - val processor = RequestProcessor(imageCapture, policy, flags, scope) + val processor = RequestProcessor(imageCapture, policy, scope) // Indicate that the screenshot belongs to a manged profile policy.setManagedProfile(USER_ID, true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt index d8821aa6aa00..3dc90374206a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt @@ -25,6 +25,7 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat +import java.lang.IllegalStateException import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runCurrent @@ -43,8 +44,11 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { private val controller0 = mock<ScreenshotController>() private val controller1 = mock<ScreenshotController>() + private val notificationsController0 = mock<ScreenshotNotificationsController>() + private val notificationsController1 = mock<ScreenshotNotificationsController>() private val controllerFactory = mock<ScreenshotController.Factory>() private val callback = mock<TakeScreenshotService.RequestCallback>() + private val notificationControllerFactory = mock<ScreenshotNotificationsController.Factory>() private val fakeDisplayRepository = FakeDisplayRepository() private val requestProcessor = FakeRequestProcessor() @@ -59,12 +63,15 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { testScope, requestProcessor, eventLogger, + notificationControllerFactory ) @Before fun setUp() { whenever(controllerFactory.create(eq(0), any())).thenReturn(controller0) whenever(controllerFactory.create(eq(1), any())).thenReturn(controller1) + whenever(notificationControllerFactory.create(eq(0))).thenReturn(notificationsController0) + whenever(notificationControllerFactory.create(eq(1))).thenReturn(notificationsController1) } @Test @@ -310,6 +317,123 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { screenshotExecutor.onDestroy() } + @Test + fun executeScreenshots_errorFromProcessor_logsScreenshotRequested() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri -> } + requestProcessor.shouldThrowException = true + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + val screenshotRequested = + eventLogger.logs.filter { + it.eventId == ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER.id + } + assertThat(screenshotRequested).hasSize(2) + screenshotExecutor.onDestroy() + } + + @Test + fun executeScreenshots_errorFromProcessor_logsUiError() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri -> } + requestProcessor.shouldThrowException = true + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + val screenshotRequested = + eventLogger.logs.filter { + it.eventId == ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED.id + } + assertThat(screenshotRequested).hasSize(2) + screenshotExecutor.onDestroy() + } + + @Test + fun executeScreenshots_errorFromProcessorOnDefaultDisplay_showsErrorNotification() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri -> } + requestProcessor.shouldThrowException = true + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + verify(notificationsController0).notifyScreenshotError(any()) + screenshotExecutor.onDestroy() + } + + @Test + fun executeScreenshots_errorFromProcessorOnSecondaryDisplay_showsErrorNotification() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0)) + val onSaved = { _: Uri -> } + requestProcessor.shouldThrowException = true + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + verify(notificationsController0).notifyScreenshotError(any()) + screenshotExecutor.onDestroy() + } + + @Test + fun executeScreenshots_errorFromScreenshotController_reportsRequested() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri -> } + whenever(controller0.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + whenever(controller1.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + val screenshotRequested = + eventLogger.logs.filter { + it.eventId == ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER.id + } + assertThat(screenshotRequested).hasSize(2) + screenshotExecutor.onDestroy() + } + + @Test + fun executeScreenshots_errorFromScreenshotController_reportsError() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri -> } + whenever(controller0.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + whenever(controller1.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + val screenshotRequested = + eventLogger.logs.filter { + it.eventId == ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED.id + } + assertThat(screenshotRequested).hasSize(2) + screenshotExecutor.onDestroy() + } + + @Test + fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri -> } + whenever(controller0.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + whenever(controller1.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + verify(notificationsController0).notifyScreenshotError(any()) + verify(notificationsController1).notifyScreenshotError(any()) + screenshotExecutor.onDestroy() + } + private suspend fun TestScope.setDisplays(vararg displays: Display) { fakeDisplayRepository.emit(displays.toSet()) runCurrent() @@ -328,8 +452,9 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { private class FakeRequestProcessor : ScreenshotRequestProcessor { var processed: ScreenshotData? = null var toReturn: ScreenshotData? = null - + var shouldThrowException = false override suspend fun process(screenshot: ScreenshotData): ScreenshotData { + if (shouldThrowException) throw RequestProcessorException("") processed = screenshot return toReturn ?: screenshot } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt index 5091a7004f79..f3809aad4de3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt @@ -65,6 +65,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { private val requestProcessor = mock<RequestProcessor>() private val devicePolicyManager = mock<DevicePolicyManager>() private val devicePolicyResourcesManager = mock<DevicePolicyResourcesManager>() + private val notificationsControllerFactory = mock<ScreenshotNotificationsController.Factory>() private val notificationsController = mock<ScreenshotNotificationsController>() private val callback = mock<RequestCallback>() @@ -87,6 +88,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { .thenReturn(false) whenever(userManager.isUserUnlocked).thenReturn(true) whenever(controllerFactory.create(any(), any())).thenReturn(controller) + whenever(notificationsControllerFactory.create(any())).thenReturn(notificationsController) // Stub request processor as a synchronous no-op for tests with the flag enabled doAnswer { @@ -323,7 +325,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { userManager, devicePolicyManager, eventLogger, - notificationsController, + notificationsControllerFactory, mContext, Runnable::run, flags, diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index 21d09792f1c7..b403a7fe8f12 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -404,5 +404,9 @@ message SystemMessage { // Notify the user that audio was lowered based on Calculated Sound Dose (CSD) NOTE_CSD_LOWER_AUDIO = 1007; + + // Notify the user about external display events related to screenshot. + // Package: com.android.systemui + NOTE_GLOBAL_SCREENSHOT_EXTERNAL_DISPLAY = 1008; } } diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index f5562d27f4e8..4298c079a63e 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -632,6 +632,10 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType, @VirtualDeviceParams.DevicePolicy int devicePolicy) { super.setDevicePolicy_enforcePermission(); + if (!Flags.dynamicPolicy()) { + return; + } + switch (policyType) { case POLICY_TYPE_RECENTS: synchronized (mVirtualDeviceLock) { diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 098cb87940b2..9f4f78794659 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; -import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; import android.hardware.display.DisplayViewport; import android.os.IBinder; import android.util.Slog; @@ -201,20 +201,6 @@ abstract class DisplayDevice { * @param state The new display state. * @param brightnessState The new display brightnessState. * @param sdrBrightnessState The new display brightnessState for SDR layers. - * @return A runnable containing work to be deferred until after we have - * exited the critical section, or null if none. - */ - public Runnable requestDisplayStateLocked(int state, float brightnessState, - float sdrBrightnessState) { - return requestDisplayStateLocked(state, brightnessState, sdrBrightnessState, null); - } - - /** - * Sets the display state, if supported. - * - * @param state The new display state. - * @param brightnessState The new display brightnessState. - * @param sdrBrightnessState The new display brightnessState for SDR layers. * @param displayOffloadSession {@link DisplayOffloadSession} associated with current device. * @return A runnable containing work to be deferred until after we have exited the critical * section, or null if none. @@ -223,7 +209,7 @@ abstract class DisplayDevice { int state, float brightnessState, float sdrBrightnessState, - @Nullable DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) { + @Nullable DisplayOffloadSession displayOffloadSession) { return null; } diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index d910e16de8e8..b0025872aa3d 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -43,6 +43,7 @@ import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; import android.annotation.Nullable; import android.content.Context; import android.graphics.Point; +import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplayConfig; import android.media.projection.IMediaProjection; @@ -395,7 +396,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { @Override public Runnable requestDisplayStateLocked(int state, float brightnessState, - float sdrBrightnessState) { + float sdrBrightnessState, DisplayOffloadSession displayOffloadSession) { if (state != mDisplayState) { mDisplayState = state; if (state == Display.STATE_OFF) { diff --git a/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java index eb997badca52..8bc69c226d1a 100644 --- a/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java +++ b/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java @@ -345,7 +345,7 @@ import java.util.Set; } private void notifyBluetoothRoutesUpdated() { - mListener.onBluetoothRoutesUpdated(getAllBluetoothRoutes()); + mListener.onBluetoothRoutesUpdated(); } private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) { diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java index 93f6ff3de3c2..33190ade4f42 100644 --- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java +++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java @@ -231,7 +231,7 @@ import java.util.Objects; } if (isDeviceRouteChanged) { - mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute); + mOnDeviceRouteChangedListener.onDeviceRouteChanged(); } } } diff --git a/services/core/java/com/android/server/media/BluetoothRouteController.java b/services/core/java/com/android/server/media/BluetoothRouteController.java index ddeeacc76579..2b01001fd7d1 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteController.java +++ b/services/core/java/com/android/server/media/BluetoothRouteController.java @@ -136,12 +136,8 @@ import java.util.Objects; */ interface BluetoothRoutesUpdatedListener { - /** - * Called when Bluetooth routes have changed. - * - * @param routes updated Bluetooth routes list. - */ - void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes); + /** Called when Bluetooth routes have changed. */ + void onBluetoothRoutesUpdated(); } /** diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java index e17f4a3fd42f..7876095a548a 100644 --- a/services/core/java/com/android/server/media/DeviceRouteController.java +++ b/services/core/java/com/android/server/media/DeviceRouteController.java @@ -93,12 +93,8 @@ import com.android.media.flags.Flags; */ interface OnDeviceRouteChangedListener { - /** - * Called when device route has changed. - * - * @param deviceRoute non-null device route. - */ - void onDeviceRouteChanged(@NonNull MediaRoute2Info deviceRoute); + /** Called when device route has changed. */ + void onDeviceRouteChanged(); } } diff --git a/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java b/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java index 198040378dc6..ba3cecf7c091 100644 --- a/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java +++ b/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java @@ -280,7 +280,7 @@ class LegacyBluetoothRouteController implements BluetoothRouteController { private void notifyBluetoothRoutesUpdated() { if (mListener != null) { - mListener.onBluetoothRoutesUpdated(getAllBluetoothRoutes()); + mListener.onBluetoothRoutesUpdated(); } } diff --git a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java index 971d11f24b9c..6ba40ae33f3c 100644 --- a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java +++ b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java @@ -165,8 +165,8 @@ import java.util.Objects; } } - private void notifyDeviceRouteUpdate(@NonNull MediaRoute2Info deviceRoute) { - mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute); + private void notifyDeviceRouteUpdate() { + mOnDeviceRouteChangedListener.onDeviceRouteChanged(); } private class AudioRoutesObserver extends IAudioRoutesObserver.Stub { @@ -177,7 +177,7 @@ import java.util.Objects; synchronized (LegacyDeviceRouteController.this) { mDeviceRoute = deviceRoute; } - notifyDeviceRouteUpdate(deviceRoute); + notifyDeviceRouteUpdate(); } } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 6c9aa4b0d849..67a1ccd17835 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -109,21 +109,28 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - mBluetoothRouteController = BluetoothRouteController.createInstance(context, (routes) -> { - publishProviderState(); - if (updateSessionInfosIfNeeded()) { - notifySessionInfoUpdated(); - } - }); - - mDeviceRouteController = DeviceRouteController.createInstance(context, (deviceRoute) -> { - mHandler.post(() -> { - publishProviderState(); - if (updateSessionInfosIfNeeded()) { - notifySessionInfoUpdated(); - } - }); - }); + mBluetoothRouteController = + BluetoothRouteController.createInstance( + context, + () -> { + publishProviderState(); + if (updateSessionInfosIfNeeded()) { + notifySessionInfoUpdated(); + } + }); + + mDeviceRouteController = + DeviceRouteController.createInstance( + context, + () -> { + mHandler.post( + () -> { + publishProviderState(); + if (updateSessionInfosIfNeeded()) { + notifySessionInfoUpdated(); + } + }); + }); mAudioManager.addOnDevicesForAttributesChangedListener( AudioAttributesUtils.ATTRIBUTES_MEDIA, mContext.getMainExecutor(), diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 0e98158d7210..7331bc141ec2 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1335,18 +1335,6 @@ public class UserManagerService extends IUserManager.Stub { && user.profileGroupId == profile.profileGroupId); } - private Intent buildProfileAvailabilityIntent(UserInfo profile, boolean enableQuietMode, - boolean useManagedActions) { - Intent intent = new Intent(); - intent.setAction(getAvailabilityIntentAction(enableQuietMode, useManagedActions)); - intent.putExtra(Intent.EXTRA_QUIET_MODE, enableQuietMode); - intent.putExtra(Intent.EXTRA_USER, profile.getUserHandle()); - intent.putExtra(Intent.EXTRA_USER_HANDLE, profile.getUserHandle().getIdentifier()); - intent.addFlags( - Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); - return intent; - } - private String getAvailabilityIntentAction(boolean enableQuietMode, boolean useManagedActions) { return useManagedActions ? enableQuietMode ? @@ -1359,12 +1347,20 @@ public class UserManagerService extends IUserManager.Stub { private void broadcastProfileAvailabilityChanges(UserInfo profileInfo, UserHandle parentHandle, boolean enableQuietMode, boolean useManagedActions) { - Intent availabilityIntent = buildProfileAvailabilityIntent(profileInfo, enableQuietMode, - useManagedActions); + Intent availabilityIntent = new Intent(); + availabilityIntent.setAction( + getAvailabilityIntentAction(enableQuietMode, useManagedActions)); + availabilityIntent.putExtra(Intent.EXTRA_QUIET_MODE, enableQuietMode); + availabilityIntent.putExtra(Intent.EXTRA_USER, profileInfo.getUserHandle()); + availabilityIntent.putExtra(Intent.EXTRA_USER_HANDLE, + profileInfo.getUserHandle().getIdentifier()); if (profileInfo.isManagedProfile()) { getDevicePolicyManagerInternal().broadcastIntentToManifestReceivers( availabilityIntent, parentHandle, /* requiresPermission= */ true); } + availabilityIntent.addFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); + // TODO(b/302708423): Restrict the apps that can receive these intents in case of a private // profile. final Bundle options = new BroadcastOptions() diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java index b039646c1697..3dc377dbc14c 100644 --- a/services/core/java/com/android/server/wm/AnimationAdapter.java +++ b/services/core/java/com/android/server/wm/AnimationAdapter.java @@ -22,6 +22,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.animation.Animation; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; @@ -31,7 +32,8 @@ import java.io.PrintWriter; * Interface that describes an animation and bridges the animation start to the component * responsible for running the animation. */ -interface AnimationAdapter { +@VisibleForTesting +public interface AnimationAdapter { long STATUS_BAR_TRANSITION_DURATION = 120L; diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index ae29afa9fc49..64a230effb38 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2023 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. @@ -11,172 +11,36 @@ * 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 + * limitations under the License. */ package com.android.server.wm; -import static com.android.server.wm.AlphaAnimationSpecProto.DURATION_MS; -import static com.android.server.wm.AlphaAnimationSpecProto.FROM; -import static com.android.server.wm.AlphaAnimationSpecProto.TO; -import static com.android.server.wm.AnimationSpecProto.ALPHA; -import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER; - import android.annotation.NonNull; import android.graphics.Rect; -import android.util.Log; -import android.util.proto.ProtoOutputStream; -import android.view.Surface; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.wm.SurfaceAnimator.AnimationType; - -import java.io.PrintWriter; +import com.android.window.flags.Flags; /** * Utility class for use by a WindowContainer implementation to add "DimLayer" support, that is * black layers of varying opacity at various Z-levels which create the effect of a Dim. */ -class Dimmer { - private static final String TAG = "WindowManager"; - // This is in milliseconds. - private static final int DEFAULT_DIM_ANIM_DURATION = 200; - - private class DimAnimatable implements SurfaceAnimator.Animatable { - private SurfaceControl mDimLayer; - - private DimAnimatable(SurfaceControl dimLayer) { - mDimLayer = dimLayer; - } - - @Override - public SurfaceControl.Transaction getSyncTransaction() { - return mHost.getSyncTransaction(); - } - - @Override - public SurfaceControl.Transaction getPendingTransaction() { - return mHost.getPendingTransaction(); - } - - @Override - public void commitPendingTransaction() { - mHost.commitPendingTransaction(); - } - - @Override - public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) { - } - - @Override - public void onAnimationLeashLost(SurfaceControl.Transaction t) { - } - - @Override - public SurfaceControl.Builder makeAnimationLeash() { - return mHost.makeAnimationLeash(); - } - - @Override - public SurfaceControl getAnimationLeashParent() { - return mHost.getSurfaceControl(); - } - - @Override - public SurfaceControl getSurfaceControl() { - return mDimLayer; - } - - @Override - public SurfaceControl getParentSurfaceControl() { - return mHost.getSurfaceControl(); - } - - @Override - public int getSurfaceWidth() { - // This will determine the size of the leash created. This should be the size of the - // host and not the dim layer since the dim layer may get bigger during animation. If - // that occurs, the leash size cannot change so we need to ensure the leash is big - // enough that the dim layer can grow. - // This works because the mHost will be a Task which has the display bounds. - return mHost.getSurfaceWidth(); - } - - @Override - public int getSurfaceHeight() { - // See getSurfaceWidth() above for explanation. - return mHost.getSurfaceHeight(); - } - - void removeSurface() { - if (mDimLayer != null && mDimLayer.isValid()) { - getSyncTransaction().remove(mDimLayer); - } - mDimLayer = null; - } - } - - @VisibleForTesting - class DimState { - /** - * The layer where property changes should be invoked on. - */ - SurfaceControl mDimLayer; - boolean mDimming; - boolean isVisible; - SurfaceAnimator mSurfaceAnimator; - - // TODO(b/64816140): Remove after confirming dimmer layer always matches its container. - final Rect mDimBounds = new Rect(); - - /** - * Determines whether the dim layer should animate before destroying. - */ - boolean mAnimateExit = true; - - /** - * Used for Dims not associated with a WindowContainer. See {@link Dimmer#dimAbove} for - * details on Dim lifecycle. - */ - boolean mDontReset; - - DimState(SurfaceControl dimLayer) { - mDimLayer = dimLayer; - mDimming = true; - final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer); - mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, (type, anim) -> { - if (!mDimming) { - dimAnimatable.removeSurface(); - } - }, mHost.mWmService); - } - } - +public abstract class Dimmer { /** - * The {@link WindowContainer} that our Dim's are bounded to. We may be dimming on behalf of the + * The {@link WindowContainer} that our Dims are bounded to. We may be dimming on behalf of the * host, some controller of it, or one of the hosts children. */ - private WindowContainer mHost; - private WindowContainer mLastRequestedDimContainer; - @VisibleForTesting - DimState mDimState; - - private final SurfaceAnimatorStarter mSurfaceAnimatorStarter; - - @VisibleForTesting - interface SurfaceAnimatorStarter { - void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, - AnimationAdapter anim, boolean hidden, @AnimationType int type); - } + protected final WindowContainer mHost; - Dimmer(WindowContainer host) { - this(host, SurfaceAnimator::startAnimation); + protected Dimmer(WindowContainer host) { + mHost = host; } - Dimmer(WindowContainer host, SurfaceAnimatorStarter surfaceAnimatorStarter) { - mHost = host; - mSurfaceAnimatorStarter = surfaceAnimatorStarter; + // Constructs the correct type of dimmer + static Dimmer create(WindowContainer host) { + return Flags.dimmerRefactor() ? new SmoothDimmer(host) : new LegacyDimmer(host); } @NonNull @@ -184,49 +48,8 @@ class Dimmer { return mHost; } - private SurfaceControl makeDimLayer() { - return mHost.makeChildSurface(null) - .setParent(mHost.getSurfaceControl()) - .setColorLayer() - .setName("Dim Layer for - " + mHost.getName()) - .setCallsite("Dimmer.makeDimLayer") - .build(); - } - - /** - * Retrieve the DimState, creating one if it doesn't exist. - */ - private DimState getDimState(WindowContainer container) { - if (mDimState == null) { - try { - final SurfaceControl ctl = makeDimLayer(); - mDimState = new DimState(ctl); - } catch (Surface.OutOfResourcesException e) { - Log.w(TAG, "OutOfResourcesException creating dim surface"); - } - } - - mLastRequestedDimContainer = container; - return mDimState; - } - - private void dim(WindowContainer container, int relativeLayer, float alpha, int blurRadius) { - final DimState d = getDimState(container); - - if (d == null) { - return; - } - - // The dim method is called from WindowState.prepareSurfaces(), which is always called - // in the correct Z from lowest Z to highest. This ensures that the dim layer is always - // relative to the highest Z layer with a dim. - SurfaceControl.Transaction t = mHost.getPendingTransaction(); - t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer); - t.setAlpha(d.mDimLayer, alpha); - t.setBackgroundBlurRadius(d.mDimLayer, blurRadius); - - d.mDimming = true; - } + protected abstract void dim( + WindowContainer container, int relativeLayer, float alpha, int blurRadius); /** * Place a dim above the given container, which should be a child of the host container. @@ -260,25 +83,15 @@ class Dimmer { * chain {@link WindowContainer#prepareSurfaces} down to it's children to give them * a chance to request dims to continue. */ - void resetDimStates() { - if (mDimState == null) { - return; - } - if (!mDimState.mDontReset) { - mDimState.mDimming = false; - } - } + abstract void resetDimStates(); /** Returns non-null bounds if the dimmer is showing. */ - Rect getDimBounds() { - return mDimState != null ? mDimState.mDimBounds : null; - } + abstract Rect getDimBounds(); - void dontAnimateExit() { - if (mDimState != null) { - mDimState.mAnimateExit = false; - } - } + abstract void dontAnimateExit(); + + @VisibleForTesting + abstract SurfaceControl getDimLayer(); /** * Call after invoking {@link WindowContainer#prepareSurfaces} on children as @@ -288,109 +101,5 @@ class Dimmer { * @param t A transaction in which to update the dims. * @return true if any Dims were updated. */ - boolean updateDims(SurfaceControl.Transaction t) { - if (mDimState == null) { - return false; - } - - if (!mDimState.mDimming) { - if (!mDimState.mAnimateExit) { - if (mDimState.mDimLayer.isValid()) { - t.remove(mDimState.mDimLayer); - } - } else { - startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t); - } - mDimState = null; - return false; - } else { - final Rect bounds = mDimState.mDimBounds; - // TODO: Once we use geometry from hierarchy this falls away. - t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top); - t.setWindowCrop(mDimState.mDimLayer, bounds.width(), bounds.height()); - if (!mDimState.isVisible) { - mDimState.isVisible = true; - t.show(mDimState.mDimLayer); - // Skip enter animation while starting window is on top of its activity - final WindowState ws = mLastRequestedDimContainer.asWindowState(); - if (ws == null || ws.mActivityRecord == null - || ws.mActivityRecord.mStartingData == null) { - startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t); - } - } - return true; - } - } - - private void startDimEnter(WindowContainer container, SurfaceAnimator animator, - SurfaceControl.Transaction t) { - startAnim(container, animator, t, 0 /* startAlpha */, 1 /* endAlpha */); - } - - private void startDimExit(WindowContainer container, SurfaceAnimator animator, - SurfaceControl.Transaction t) { - startAnim(container, animator, t, 1 /* startAlpha */, 0 /* endAlpha */); - } - - private void startAnim(WindowContainer container, SurfaceAnimator animator, - SurfaceControl.Transaction t, float startAlpha, float endAlpha) { - mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter( - new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)), - mHost.mWmService.mSurfaceAnimationRunner), false /* hidden */, - ANIMATION_TYPE_DIMMER); - } - - private long getDimDuration(WindowContainer container) { - // If there's no container, then there isn't an animation occurring while dimming. Set the - // duration to 0 so it immediately dims to the set alpha. - if (container == null) { - return 0; - } - - // Otherwise use the same duration as the animation on the WindowContainer - AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation(); - final float durationScale = container.mWmService.getTransitionAnimationScaleLocked(); - return animationAdapter == null ? (long) (DEFAULT_DIM_ANIM_DURATION * durationScale) - : animationAdapter.getDurationHint(); - } - - private static class AlphaAnimationSpec implements LocalAnimationAdapter.AnimationSpec { - private final long mDuration; - private final float mFromAlpha; - private final float mToAlpha; - - AlphaAnimationSpec(float fromAlpha, float toAlpha, long duration) { - mFromAlpha = fromAlpha; - mToAlpha = toAlpha; - mDuration = duration; - } - - @Override - public long getDuration() { - return mDuration; - } - - @Override - public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) { - final float fraction = getFraction(currentPlayTime); - final float alpha = fraction * (mToAlpha - mFromAlpha) + mFromAlpha; - t.setAlpha(sc, alpha); - } - - @Override - public void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("from="); pw.print(mFromAlpha); - pw.print(" to="); pw.print(mToAlpha); - pw.print(" duration="); pw.println(mDuration); - } - - @Override - public void dumpDebugInner(ProtoOutputStream proto) { - final long token = proto.start(ALPHA); - proto.write(FROM, mFromAlpha); - proto.write(TO, mToAlpha); - proto.write(DURATION_MS, mDuration); - proto.end(token); - } - } + abstract boolean updateDims(SurfaceControl.Transaction t); } diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index df26b101a657..f51bf7fbf27a 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -54,7 +54,6 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; - /** * Container for grouping WindowContainer below DisplayContent. * @@ -786,7 +785,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { * DisplayArea that can be dimmed. */ static class Dimmable extends DisplayArea<DisplayArea> { - private final Dimmer mDimmer = new Dimmer(this); + private final Dimmer mDimmer = Dimmer.create(this); Dimmable(WindowManagerService wms, Type type, String name, int featureId) { super(wms, type, name, featureId); diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index c21930dab5eb..1fa7d2a2aa13 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -51,7 +51,8 @@ class InputConsumerImpl implements IBinder.DeathRecipient { private final Rect mOldWindowCrop = new Rect(); InputConsumerImpl(WindowManagerService service, IBinder token, String name, - InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId) { + InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId, + SurfaceControl.Transaction t) { mService = service; mToken = token; mName = name; @@ -82,6 +83,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient { .setName("Input Consumer " + name) .setCallsite("InputConsumerImpl") .build(); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); } void linkToDeathRecipient() { @@ -129,14 +131,12 @@ class InputConsumerImpl implements IBinder.DeathRecipient { void show(SurfaceControl.Transaction t, WindowContainer w) { t.show(mInputSurface); - mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1); } void show(SurfaceControl.Transaction t, int layer) { t.show(mInputSurface); - mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setLayer(mInputSurface, layer); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index af307ec3c2a9..5c0bc28779a8 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -224,7 +224,7 @@ final class InputMonitor { } final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name, - inputChannel, clientPid, clientUser, mDisplayId); + inputChannel, clientPid, clientUser, mDisplayId, mInputTransaction); switch (name) { case INPUT_CONSUMER_WALLPAPER: consumer.mWindowHandle.inputConfig |= InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER; @@ -675,11 +675,6 @@ final class InputMonitor { w.getKeyInterceptionInfo()); if (w.mWinAnimator.hasSurface()) { - // Update trusted overlay changes here because they are tied to input info. Input - // changes can be updated even if surfaces aren't. - inputWindowHandle.setTrustedOverlay(mInputTransaction, - w.mWinAnimator.mSurfaceController.mSurfaceControl, - w.isWindowTrustedOverlay()); populateInputWindowHandle(inputWindowHandle, w); setInputWindowInfoIfNeeded(mInputTransaction, w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle); diff --git a/services/core/java/com/android/server/wm/LegacyDimmer.java b/services/core/java/com/android/server/wm/LegacyDimmer.java new file mode 100644 index 000000000000..ccf956ecef1e --- /dev/null +++ b/services/core/java/com/android/server/wm/LegacyDimmer.java @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2023 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.server.wm.AlphaAnimationSpecProto.DURATION_MS; +import static com.android.server.wm.AlphaAnimationSpecProto.FROM; +import static com.android.server.wm.AlphaAnimationSpecProto.TO; +import static com.android.server.wm.AnimationSpecProto.ALPHA; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import android.graphics.Rect; +import android.util.Log; +import android.util.proto.ProtoOutputStream; +import android.view.Surface; +import android.view.SurfaceControl; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.PrintWriter; + +public class LegacyDimmer extends Dimmer { + private static final String TAG = TAG_WITH_CLASS_NAME ? "Dimmer" : TAG_WM; + // This is in milliseconds. + private static final int DEFAULT_DIM_ANIM_DURATION = 200; + DimState mDimState; + private WindowContainer mLastRequestedDimContainer; + private final SurfaceAnimatorStarter mSurfaceAnimatorStarter; + + private class DimAnimatable implements SurfaceAnimator.Animatable { + private SurfaceControl mDimLayer; + + private DimAnimatable(SurfaceControl dimLayer) { + mDimLayer = dimLayer; + } + + @Override + public SurfaceControl.Transaction getSyncTransaction() { + return mHost.getSyncTransaction(); + } + + @Override + public SurfaceControl.Transaction getPendingTransaction() { + return mHost.getPendingTransaction(); + } + + @Override + public void commitPendingTransaction() { + mHost.commitPendingTransaction(); + } + + @Override + public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) { + } + + @Override + public void onAnimationLeashLost(SurfaceControl.Transaction t) { + } + + @Override + public SurfaceControl.Builder makeAnimationLeash() { + return mHost.makeAnimationLeash(); + } + + @Override + public SurfaceControl getAnimationLeashParent() { + return mHost.getSurfaceControl(); + } + + @Override + public SurfaceControl getSurfaceControl() { + return mDimLayer; + } + + @Override + public SurfaceControl getParentSurfaceControl() { + return mHost.getSurfaceControl(); + } + + @Override + public int getSurfaceWidth() { + // This will determine the size of the leash created. This should be the size of the + // host and not the dim layer since the dim layer may get bigger during animation. If + // that occurs, the leash size cannot change so we need to ensure the leash is big + // enough that the dim layer can grow. + // This works because the mHost will be a Task which has the display bounds. + return mHost.getSurfaceWidth(); + } + + @Override + public int getSurfaceHeight() { + // See getSurfaceWidth() above for explanation. + return mHost.getSurfaceHeight(); + } + + void removeSurface() { + if (mDimLayer != null && mDimLayer.isValid()) { + getSyncTransaction().remove(mDimLayer); + } + mDimLayer = null; + } + } + + @VisibleForTesting + class DimState { + /** + * The layer where property changes should be invoked on. + */ + SurfaceControl mDimLayer; + boolean mDimming; + boolean mIsVisible; + + // TODO(b/64816140): Remove after confirming dimmer layer always matches its container. + final Rect mDimBounds = new Rect(); + + /** + * Determines whether the dim layer should animate before destroying. + */ + boolean mAnimateExit = true; + + /** + * Used for Dims not associated with a WindowContainer. See {@link Dimmer#dimAbove} for + * details on Dim lifecycle. + */ + boolean mDontReset; + SurfaceAnimator mSurfaceAnimator; + + DimState(SurfaceControl dimLayer) { + mDimLayer = dimLayer; + mDimming = true; + final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer); + mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, (type, anim) -> { + if (!mDimming) { + dimAnimatable.removeSurface(); + } + }, mHost.mWmService); + } + } + + @VisibleForTesting + interface SurfaceAnimatorStarter { + void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, + AnimationAdapter anim, boolean hidden, @SurfaceAnimator.AnimationType int type); + } + + protected LegacyDimmer(WindowContainer host) { + this(host, SurfaceAnimator::startAnimation); + } + + LegacyDimmer(WindowContainer host, SurfaceAnimatorStarter surfaceAnimatorStarter) { + super(host); + mSurfaceAnimatorStarter = surfaceAnimatorStarter; + } + + private DimState obtainDimState(WindowContainer container) { + if (mDimState == null) { + try { + final SurfaceControl ctl = makeDimLayer(); + mDimState = new DimState(ctl); + } catch (Surface.OutOfResourcesException e) { + Log.w(TAG, "OutOfResourcesException creating dim surface"); + } + } + + mLastRequestedDimContainer = container; + return mDimState; + } + + private SurfaceControl makeDimLayer() { + return mHost.makeChildSurface(null) + .setParent(mHost.getSurfaceControl()) + .setColorLayer() + .setName("Dim Layer for - " + mHost.getName()) + .setCallsite("Dimmer.makeDimLayer") + .build(); + } + + @Override + SurfaceControl getDimLayer() { + return mDimState != null ? mDimState.mDimLayer : null; + } + + @Override + void resetDimStates() { + if (mDimState == null) { + return; + } + if (!mDimState.mDontReset) { + mDimState.mDimming = false; + } + } + + @Override + Rect getDimBounds() { + return mDimState != null ? mDimState.mDimBounds : null; + } + + @Override + void dontAnimateExit() { + if (mDimState != null) { + mDimState.mAnimateExit = false; + } + } + + @Override + protected void dim(WindowContainer container, int relativeLayer, float alpha, int blurRadius) { + final DimState d = obtainDimState(container); + + if (d == null) { + return; + } + + // The dim method is called from WindowState.prepareSurfaces(), which is always called + // in the correct Z from lowest Z to highest. This ensures that the dim layer is always + // relative to the highest Z layer with a dim. + SurfaceControl.Transaction t = mHost.getPendingTransaction(); + t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer); + t.setAlpha(d.mDimLayer, alpha); + t.setBackgroundBlurRadius(d.mDimLayer, blurRadius); + + d.mDimming = true; + } + + @Override + boolean updateDims(SurfaceControl.Transaction t) { + if (mDimState == null) { + return false; + } + + if (!mDimState.mDimming) { + if (!mDimState.mAnimateExit) { + if (mDimState.mDimLayer.isValid()) { + t.remove(mDimState.mDimLayer); + } + } else { + startDimExit(mLastRequestedDimContainer, + mDimState.mSurfaceAnimator, t); + } + mDimState = null; + return false; + } else { + final Rect bounds = mDimState.mDimBounds; + // TODO: Once we use geometry from hierarchy this falls away. + t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top); + t.setWindowCrop(mDimState.mDimLayer, bounds.width(), bounds.height()); + if (!mDimState.mIsVisible) { + mDimState.mIsVisible = true; + t.show(mDimState.mDimLayer); + // Skip enter animation while starting window is on top of its activity + final WindowState ws = mLastRequestedDimContainer.asWindowState(); + if (ws == null || ws.mActivityRecord == null + || ws.mActivityRecord.mStartingData == null) { + startDimEnter(mLastRequestedDimContainer, + mDimState.mSurfaceAnimator, t); + } + } + return true; + } + } + + private long getDimDuration(WindowContainer container) { + // Use the same duration as the animation on the WindowContainer + AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation(); + final float durationScale = container.mWmService.getTransitionAnimationScaleLocked(); + return animationAdapter == null ? (long) (DEFAULT_DIM_ANIM_DURATION * durationScale) + : animationAdapter.getDurationHint(); + } + + private void startDimEnter(WindowContainer container, SurfaceAnimator animator, + SurfaceControl.Transaction t) { + startAnim(container, animator, t, 0 /* startAlpha */, 1 /* endAlpha */); + } + + private void startDimExit(WindowContainer container, SurfaceAnimator animator, + SurfaceControl.Transaction t) { + startAnim(container, animator, t, 1 /* startAlpha */, 0 /* endAlpha */); + } + + private void startAnim(WindowContainer container, SurfaceAnimator animator, + SurfaceControl.Transaction t, float startAlpha, float endAlpha) { + mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter( + new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)), + mHost.mWmService.mSurfaceAnimationRunner), false /* hidden */, + ANIMATION_TYPE_DIMMER); + } + + private static class AlphaAnimationSpec implements LocalAnimationAdapter.AnimationSpec { + private final long mDuration; + private final float mFromAlpha; + private final float mToAlpha; + + AlphaAnimationSpec(float fromAlpha, float toAlpha, long duration) { + mFromAlpha = fromAlpha; + mToAlpha = toAlpha; + mDuration = duration; + } + + @Override + public long getDuration() { + return mDuration; + } + + @Override + public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) { + final float fraction = getFraction(currentPlayTime); + final float alpha = fraction * (mToAlpha - mFromAlpha) + mFromAlpha; + t.setAlpha(sc, alpha); + } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("from="); pw.print(mFromAlpha); + pw.print(" to="); pw.print(mToAlpha); + pw.print(" duration="); pw.println(mDuration); + } + + @Override + public void dumpDebugInner(ProtoOutputStream proto) { + final long token = proto.start(ALPHA); + proto.write(FROM, mFromAlpha); + proto.write(TO, mToAlpha); + proto.write(DURATION_MS, mDuration); + proto.end(token); + } + } +} diff --git a/services/core/java/com/android/server/wm/SmoothDimmer.java b/services/core/java/com/android/server/wm/SmoothDimmer.java new file mode 100644 index 000000000000..6ddbd2c8eb67 --- /dev/null +++ b/services/core/java/com/android/server/wm/SmoothDimmer.java @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2023 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.internal.protolog.ProtoLogGroup.WM_DEBUG_DIMMER; +import static com.android.server.wm.AlphaAnimationSpecProto.DURATION_MS; +import static com.android.server.wm.AlphaAnimationSpecProto.FROM; +import static com.android.server.wm.AlphaAnimationSpecProto.TO; +import static com.android.server.wm.AnimationSpecProto.ALPHA; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import android.graphics.Rect; +import android.util.Log; +import android.util.proto.ProtoOutputStream; +import android.view.Surface; +import android.view.SurfaceControl; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; + +import java.io.PrintWriter; + +class SmoothDimmer extends Dimmer { + private static final String TAG = TAG_WITH_CLASS_NAME ? "Dimmer" : TAG_WM; + private static final float EPSILON = 0.0001f; + // This is in milliseconds. + private static final int DEFAULT_DIM_ANIM_DURATION = 200; + DimState mDimState; + private WindowContainer mLastRequestedDimContainer; + private final AnimationAdapterFactory mAnimationAdapterFactory; + + @VisibleForTesting + class DimState { + /** + * The layer where property changes should be invoked on. + */ + SurfaceControl mDimLayer; + boolean mDimming; + boolean mIsVisible; + + // TODO(b/64816140): Remove after confirming dimmer layer always matches its container. + final Rect mDimBounds = new Rect(); + + /** + * Determines whether the dim layer should animate before destroying. + */ + boolean mAnimateExit = true; + + /** + * Used for Dims not associated with a WindowContainer. See {@link Dimmer#dimAbove} for + * details on Dim lifecycle. + */ + boolean mDontReset; + + Change mCurrentProperties; + Change mRequestedProperties; + private AnimationSpec mAlphaAnimationSpec; + private AnimationAdapter mLocalAnimationAdapter; + + static class Change { + private float mAlpha = -1f; + private int mBlurRadius = -1; + private WindowContainer mDimmingContainer = null; + private int mRelativeLayer = -1; + private boolean mSkipAnimation = false; + + Change() {} + + Change(Change other) { + mAlpha = other.mAlpha; + mBlurRadius = other.mBlurRadius; + mDimmingContainer = other.mDimmingContainer; + mRelativeLayer = other.mRelativeLayer; + } + + @Override + public String toString() { + return "Dim state: alpha=" + mAlpha + ", blur=" + mBlurRadius + ", container=" + + mDimmingContainer + ", relativePosition=" + mRelativeLayer + + ", skipAnimation=" + mSkipAnimation; + } + } + + DimState(SurfaceControl dimLayer) { + mDimLayer = dimLayer; + mDimming = true; + mCurrentProperties = new Change(); + mRequestedProperties = new Change(); + } + + void setExitParameters(WindowContainer container) { + setRequestedParameters(container, -1, 0, 0); + } + // Sets a requested change without applying it immediately + void setRequestedParameters(WindowContainer container, int relativeLayer, float alpha, + int blurRadius) { + mRequestedProperties.mDimmingContainer = container; + mRequestedProperties.mRelativeLayer = relativeLayer; + mRequestedProperties.mAlpha = alpha; + mRequestedProperties.mBlurRadius = blurRadius; + } + + /** + * Commit the last changes we received. Called after + * {@link Change#setRequestedParameters(WindowContainer, int, float, int)} + */ + void applyChanges(SurfaceControl.Transaction t) { + if (mRequestedProperties.mDimmingContainer.mSurfaceControl == null) { + Log.w(TAG, "container " + mRequestedProperties.mDimmingContainer + + "does not have a surface"); + return; + } + if (!mDimState.mIsVisible) { + mDimState.mIsVisible = true; + t.show(mDimState.mDimLayer); + } + t.setRelativeLayer(mDimLayer, + mRequestedProperties.mDimmingContainer.getSurfaceControl(), + mRequestedProperties.mRelativeLayer); + + if (aspectChanged()) { + if (isAnimating()) { + mLocalAnimationAdapter.onAnimationCancelled(mDimLayer); + } + if (mRequestedProperties.mSkipAnimation + || (!dimmingContainerChanged() && mDimming)) { + // If the dimming container has not changed, then it is running its own + // animation, thus we can directly set the values we get requested, unless it's + // the exiting animation + ProtoLog.d(WM_DEBUG_DIMMER, + "Dim %s skipping animation and directly setting alpha=%f, blur=%d", + mDimLayer, mRequestedProperties.mAlpha, + mRequestedProperties.mBlurRadius); + t.setAlpha(mDimLayer, mRequestedProperties.mAlpha); + t.setBackgroundBlurRadius(mDimLayer, mRequestedProperties.mBlurRadius); + mRequestedProperties.mSkipAnimation = false; + } else { + startAnimation(t); + } + } + mCurrentProperties = new Change(mRequestedProperties); + } + + private void startAnimation(SurfaceControl.Transaction t) { + mAlphaAnimationSpec = getRequestedAnimationSpec(mRequestedProperties.mAlpha, + mRequestedProperties.mBlurRadius); + mLocalAnimationAdapter = mAnimationAdapterFactory.get(mAlphaAnimationSpec, + mHost.mWmService.mSurfaceAnimationRunner); + + mLocalAnimationAdapter.startAnimation(mDimLayer, t, + ANIMATION_TYPE_DIMMER, (type, animator) -> { + t.setAlpha(mDimLayer, mRequestedProperties.mAlpha); + t.setBackgroundBlurRadius(mDimLayer, mRequestedProperties.mBlurRadius); + if (mRequestedProperties.mAlpha == 0f && !mDimming) { + ProtoLog.d(WM_DEBUG_DIMMER, + "Removing dim surface %s on transaction %s", mDimLayer, t); + t.remove(mDimLayer); + } + mLocalAnimationAdapter = null; + mAlphaAnimationSpec = null; + }); + } + + private boolean isAnimating() { + return mAlphaAnimationSpec != null; + } + + private boolean aspectChanged() { + return Math.abs(mRequestedProperties.mAlpha - mCurrentProperties.mAlpha) > EPSILON + || mRequestedProperties.mBlurRadius != mCurrentProperties.mBlurRadius; + } + + private boolean dimmingContainerChanged() { + return mRequestedProperties.mDimmingContainer != mCurrentProperties.mDimmingContainer; + } + + private AnimationSpec getRequestedAnimationSpec(float targetAlpha, int targetBlur) { + final float startAlpha; + final int startBlur; + if (mAlphaAnimationSpec != null) { + startAlpha = mAlphaAnimationSpec.mCurrentAlpha; + startBlur = mAlphaAnimationSpec.mCurrentBlur; + } else { + startAlpha = Math.max(mCurrentProperties.mAlpha, 0f); + startBlur = Math.max(mCurrentProperties.mBlurRadius, 0); + } + long duration = (long) (getDimDuration(mRequestedProperties.mDimmingContainer) + * Math.abs(targetAlpha - startAlpha)); + + ProtoLog.v(WM_DEBUG_DIMMER, "Starting animation on dim layer %s, requested by %s, " + + "alpha: %f -> %f, blur: %d -> %d", + mDimLayer, mRequestedProperties.mDimmingContainer, startAlpha, targetAlpha, + startBlur, targetBlur); + return new AnimationSpec( + new AnimationExtremes<>(startAlpha, targetAlpha), + new AnimationExtremes<>(startBlur, targetBlur), + duration + ); + } + } + + protected SmoothDimmer(WindowContainer host) { + this(host, new AnimationAdapterFactory()); + } + + @VisibleForTesting + SmoothDimmer(WindowContainer host, AnimationAdapterFactory animationFactory) { + super(host); + mAnimationAdapterFactory = animationFactory; + } + + private DimState obtainDimState(WindowContainer container) { + if (mDimState == null) { + try { + final SurfaceControl ctl = makeDimLayer(); + mDimState = new DimState(ctl); + } catch (Surface.OutOfResourcesException e) { + Log.w(TAG, "OutOfResourcesException creating dim surface"); + } + } + + mLastRequestedDimContainer = container; + return mDimState; + } + + private SurfaceControl makeDimLayer() { + return mHost.makeChildSurface(null) + .setParent(mHost.getSurfaceControl()) + .setColorLayer() + .setName("Dim Layer for - " + mHost.getName()) + .setCallsite("Dimmer.makeDimLayer") + .build(); + } + + @Override + SurfaceControl getDimLayer() { + return mDimState != null ? mDimState.mDimLayer : null; + } + + @Override + void resetDimStates() { + if (mDimState == null) { + return; + } + if (!mDimState.mDontReset) { + mDimState.mDimming = false; + } + } + + @Override + Rect getDimBounds() { + return mDimState != null ? mDimState.mDimBounds : null; + } + + @Override + void dontAnimateExit() { + if (mDimState != null) { + mDimState.mAnimateExit = false; + } + } + + @Override + protected void dim(WindowContainer container, int relativeLayer, float alpha, int blurRadius) { + final DimState d = obtainDimState(container); + + mDimState.mRequestedProperties.mDimmingContainer = container; + mDimState.setRequestedParameters(container, relativeLayer, alpha, blurRadius); + d.mDimming = true; + } + + boolean updateDims(SurfaceControl.Transaction t) { + if (mDimState == null) { + return false; + } + + if (!mDimState.mDimming) { + // No one is dimming anymore, fade out dim and remove + if (!mDimState.mAnimateExit) { + if (mDimState.mDimLayer.isValid()) { + t.remove(mDimState.mDimLayer); + } + } else { + mDimState.setExitParameters( + mDimState.mRequestedProperties.mDimmingContainer); + mDimState.applyChanges(t); + } + mDimState = null; + return false; + } + final Rect bounds = mDimState.mDimBounds; + // TODO: Once we use geometry from hierarchy this falls away. + t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top); + t.setWindowCrop(mDimState.mDimLayer, bounds.width(), bounds.height()); + // Skip enter animation while starting window is on top of its activity + final WindowState ws = mLastRequestedDimContainer.asWindowState(); + if (!mDimState.mIsVisible && ws != null && ws.mActivityRecord != null + && ws.mActivityRecord.mStartingData != null) { + mDimState.mRequestedProperties.mSkipAnimation = true; + } + mDimState.applyChanges(t); + return true; + } + + private long getDimDuration(WindowContainer container) { + // Use the same duration as the animation on the WindowContainer + AnimationAdapter animationAdapter = container.mSurfaceAnimator.getAnimation(); + final float durationScale = container.mWmService.getTransitionAnimationScaleLocked(); + return animationAdapter == null ? (long) (DEFAULT_DIM_ANIM_DURATION * durationScale) + : animationAdapter.getDurationHint(); + } + + private static class AnimationExtremes<T> { + final T mStartValue; + final T mFinishValue; + + AnimationExtremes(T fromValue, T toValue) { + mStartValue = fromValue; + mFinishValue = toValue; + } + } + + private static class AnimationSpec implements LocalAnimationAdapter.AnimationSpec { + private final long mDuration; + private final AnimationExtremes<Float> mAlpha; + private final AnimationExtremes<Integer> mBlur; + + float mCurrentAlpha = 0; + int mCurrentBlur = 0; + + AnimationSpec(AnimationExtremes<Float> alpha, + AnimationExtremes<Integer> blur, long duration) { + mAlpha = alpha; + mBlur = blur; + mDuration = duration; + } + + @Override + public long getDuration() { + return mDuration; + } + + @Override + public void apply(SurfaceControl.Transaction t, SurfaceControl sc, long currentPlayTime) { + final float fraction = getFraction(currentPlayTime); + mCurrentAlpha = + fraction * (mAlpha.mFinishValue - mAlpha.mStartValue) + mAlpha.mStartValue; + mCurrentBlur = + (int) fraction * (mBlur.mFinishValue - mBlur.mStartValue) + mBlur.mStartValue; + t.setAlpha(sc, mCurrentAlpha); + t.setBackgroundBlurRadius(sc, mCurrentBlur); + } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("from_alpha="); pw.print(mAlpha.mStartValue); + pw.print(" to_alpha="); pw.print(mAlpha.mFinishValue); + pw.print(prefix); pw.print("from_blur="); pw.print(mBlur.mStartValue); + pw.print(" to_blur="); pw.print(mBlur.mFinishValue); + pw.print(" duration="); pw.println(mDuration); + } + + @Override + public void dumpDebugInner(ProtoOutputStream proto) { + final long token = proto.start(ALPHA); + proto.write(FROM, mAlpha.mStartValue); + proto.write(TO, mAlpha.mFinishValue); + proto.write(DURATION_MS, mDuration); + proto.end(token); + } + } + + static class AnimationAdapterFactory { + + public AnimationAdapter get(LocalAnimationAdapter.AnimationSpec alphaAnimationSpec, + SurfaceAnimationRunner runner) { + return new LocalAnimationAdapter(alphaAnimationSpec, runner); + } + } +} diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 408ea6eb8c1a..c3de4d5acc21 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -49,7 +49,8 @@ import java.util.function.Supplier; * {@link AnimationAdapter}. When the animation is done animating, our callback to finish the * animation will be invoked, at which we reparent the children back to the original parent. */ -class SurfaceAnimator { +@VisibleForTesting +public class SurfaceAnimator { private static final String TAG = TAG_WITH_CLASS_NAME ? "SurfaceAnimator" : TAG_WM; @@ -617,7 +618,8 @@ class SurfaceAnimator { * Callback to be passed into {@link AnimationAdapter#startAnimation} to be invoked by the * component that is running the animation when the animation is finished. */ - interface OnAnimationFinishedCallback { + @VisibleForTesting + public interface OnAnimationFinishedCallback { void onAnimationFinished(@AnimationType int type, AnimationAdapter anim); } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 50bc825d8bea..4a3314d012a0 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -103,6 +103,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.server.am.HostingRecord; import com.android.server.pm.pkg.AndroidPackage; +import com.android.window.flags.Flags; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -209,7 +210,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { */ int mMinHeight; - Dimmer mDimmer = new Dimmer(this); + Dimmer mDimmer = Flags.dimmerRefactor() + ? new SmoothDimmer(this) : new LegacyDimmer(this); /** This task fragment will be removed when the cleanup of its children are done. */ private boolean mIsRemovalRequested; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f339d249e272..9663f3aba7f1 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2261,6 +2261,7 @@ public class WindowManagerService extends IWindowManager.Stub } } + final boolean wasTrustedOverlay = win.isWindowTrustedOverlay(); flagChanges = win.mAttrs.flags ^ attrs.flags; privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags; attrChanges = win.mAttrs.copyFrom(attrs); @@ -2273,6 +2274,9 @@ public class WindowManagerService extends IWindowManager.Stub if (layoutChanged && win.providesDisplayDecorInsets()) { configChanged = displayPolicy.updateDecorInsetsInfo(); } + if (wasTrustedOverlay != win.isWindowTrustedOverlay()) { + win.updateTrustedOverlay(); + } if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0 || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) { win.mActivityRecord.checkKeyguardFlagsChanged(); @@ -5299,7 +5303,11 @@ public class WindowManagerService extends IWindowManager.Stub public void displayReady() { synchronized (mGlobalLock) { if (mMaxUiWidth > 0) { - mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth)); + mRoot.forAllDisplays(dc -> { + if (dc.mDisplay.getType() == Display.TYPE_INTERNAL) { + dc.setMaxUiWidth(mMaxUiWidth); + } + }); } applyForcedPropertiesForDefaultDisplay(); mAnimator.ready(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 726d4d7c34e7..87312a37743d 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1189,7 +1189,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - public boolean isWindowTrustedOverlay() { + @Override + void setInitialSurfaceControlProperties(SurfaceControl.Builder b) { + super.setInitialSurfaceControlProperties(b); + if (surfaceTrustedOverlay() && isWindowTrustedOverlay()) { + getPendingTransaction().setTrustedOverlay(mSurfaceControl, true); + } + } + + void updateTrustedOverlay() { + mInputWindowHandle.setTrustedOverlay(getPendingTransaction(), mSurfaceControl, + isWindowTrustedOverlay()); + } + + boolean isWindowTrustedOverlay() { return InputMonitor.isTrustedOverlay(mAttrs.type) || ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0 && mSession.mCanAddInternalSystemWindow) @@ -5205,9 +5218,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP updateFrameRateSelectionPriorityIfNeeded(); updateScaleIfNeeded(); mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); - if (surfaceTrustedOverlay()) { - getSyncTransaction().setTrustedOverlay(mSurfaceControl, isWindowTrustedOverlay()); - } } super.prepareSurfaces(); } diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java index 9ac00624b343..32e28715cc74 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -33,6 +33,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; import android.content.Context; @@ -699,7 +700,7 @@ public class LocalDisplayAdapterTest { // Turn off. Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_OFF, 0, - 0); + 0, null); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(mListener.changedDisplays.size()).isEqualTo(1); mListener.changedDisplays.clear(); @@ -1003,7 +1004,7 @@ public class LocalDisplayAdapterTest { // Turn on / initialize assumeTrue(displayDevice.getDisplayDeviceConfig().hasSdrToHdrRatioSpline()); Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 0, - 0); + 0, null); changeStateRunnable.run(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); mListener.changedDisplays.clear(); @@ -1012,7 +1013,7 @@ public class LocalDisplayAdapterTest { // HDR time! Runnable goHdrRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 1f, - 0); + 0, null); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); // Display state didn't change, no listeners should have happened assertThat(mListener.changedDisplays.size()).isEqualTo(0); @@ -1043,7 +1044,7 @@ public class LocalDisplayAdapterTest { // Turn on / initialize Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 0, - 0); + 0, null); changeStateRunnable.run(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); mListener.changedDisplays.clear(); @@ -1070,7 +1071,7 @@ public class LocalDisplayAdapterTest { // Turn on / initialize Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 0, - 0); + 0, null); changeStateRunnable.run(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); mListener.changedDisplays.clear(); @@ -1095,7 +1096,7 @@ public class LocalDisplayAdapterTest { // Turn on / initialize Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 0, - 0); + 0, null); changeStateRunnable.run(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); mListener.changedDisplays.clear(); @@ -1118,7 +1119,7 @@ public class LocalDisplayAdapterTest { // Turn on / initialize Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 0, - 0); + 0, null); changeStateRunnable.run(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); mListener.changedDisplays.clear(); @@ -1145,9 +1146,9 @@ public class LocalDisplayAdapterTest { Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked( supportedState, 0, 0, mDisplayOffloadSession); changeStateRunnable.run(); - - verify(mDisplayOffloader).startOffload(); } + + verify(mDisplayOffloader, times(mDisplayOffloadSupportedStates.size())).startOffload(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/media/BluetoothRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/BluetoothRouteControllerTest.java index 75d71daa208d..06f117bdbd65 100644 --- a/services/tests/servicestests/src/com/android/server/media/BluetoothRouteControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/BluetoothRouteControllerTest.java @@ -38,9 +38,10 @@ import org.junit.runners.JUnit4; public class BluetoothRouteControllerTest { private final BluetoothRouteController.BluetoothRoutesUpdatedListener - mBluetoothRoutesUpdatedListener = routes -> { - // Empty on purpose. - }; + mBluetoothRoutesUpdatedListener = + () -> { + // Empty on purpose. + }; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); diff --git a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java index ec4b8a804533..14b121d3945c 100644 --- a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java @@ -38,7 +38,7 @@ import org.junit.runners.JUnit4; public class DeviceRouteControllerTest { private final DeviceRouteController.OnDeviceRouteChangedListener mOnDeviceRouteChangedListener = - deviceRoute -> { + () -> { // Empty on purpose. }; diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index 233a2076a867..84d42d42f834 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -18,16 +18,20 @@ package com.android.server.wm; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER; +import static com.android.server.wm.utils.LastCallVerifier.lastCall; import static org.junit.Assert.assertNotNull; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; import android.graphics.Rect; @@ -35,8 +39,9 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; -import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.testutils.StubTransaction; +import com.android.server.wm.utils.MockAnimationAdapter; +import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; @@ -118,102 +123,168 @@ public class DimmerTests extends WindowTestsBase { } } - private MockSurfaceBuildingContainer mHost; - private Dimmer mDimmer; - private SurfaceControl.Transaction mTransaction; - private Dimmer.SurfaceAnimatorStarter mSurfaceAnimatorStarter; + static class MockAnimationAdapterFactory extends SmoothDimmer.AnimationAdapterFactory { + public AnimationAdapter get(LocalAnimationAdapter.AnimationSpec alphaAnimationSpec, + SurfaceAnimationRunner runner) { + return sTestAnimation; + } + } - private static class SurfaceAnimatorStarterImpl implements Dimmer.SurfaceAnimatorStarter { + private static class SurfaceAnimatorStarterImpl implements LegacyDimmer.SurfaceAnimatorStarter { @Override public void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, - AnimationAdapter anim, boolean hidden, @AnimationType int type) { + AnimationAdapter anim, boolean hidden, @SurfaceAnimator.AnimationType int type) { surfaceAnimator.mStaticAnimationFinishedCallback.onAnimationFinished(type, anim); } } + private MockSurfaceBuildingContainer mHost; + private Dimmer mDimmer; + private SurfaceControl.Transaction mTransaction; + private TestWindowContainer mChild; + private static AnimationAdapter sTestAnimation; + private static LegacyDimmer.SurfaceAnimatorStarter sSurfaceAnimatorStarter; + @Before public void setUp() throws Exception { mHost = new MockSurfaceBuildingContainer(mWm); - mSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl()); mTransaction = spy(StubTransaction.class); - mDimmer = new Dimmer(mHost, mSurfaceAnimatorStarter); + mChild = new TestWindowContainer(mWm); + if (Flags.dimmerRefactor()) { + sTestAnimation = spy(new MockAnimationAdapter()); + mDimmer = new SmoothDimmer(mHost, new MockAnimationAdapterFactory()); + } else { + sSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl()); + mDimmer = new LegacyDimmer(mHost, sSurfaceAnimatorStarter); + } } @Test public void testUpdateDimsAppliesCrop() { - TestWindowContainer child = new TestWindowContainer(mWm); - mHost.addChild(child, 0); + mHost.addChild(mChild, 0); final float alpha = 0.8f; - mDimmer.dimAbove(child, alpha); + mDimmer.dimAbove(mChild, alpha); int width = 100; int height = 300; - mDimmer.mDimState.mDimBounds.set(0, 0, width, height); + mDimmer.getDimBounds().set(0, 0, width, height); mDimmer.updateDims(mTransaction); - verify(mTransaction).setWindowCrop(getDimLayer(), width, height); - verify(mTransaction).show(getDimLayer()); + verify(mTransaction).setWindowCrop(mDimmer.getDimLayer(), width, height); + verify(mTransaction).show(mDimmer.getDimLayer()); } @Test - public void testDimAboveWithChildCreatesSurfaceAboveChild() { - TestWindowContainer child = new TestWindowContainer(mWm); - mHost.addChild(child, 0); + public void testDimAboveWithChildCreatesSurfaceAboveChild_Smooth() { + assumeTrue(Flags.dimmerRefactor()); + final float alpha = 0.8f; + mHost.addChild(mChild, 0); + mDimmer.dimAbove(mChild, alpha); + SurfaceControl dimLayer = mDimmer.getDimLayer(); + + assertNotNull("Dimmer should have created a surface", dimLayer); + + mDimmer.updateDims(mTransaction); + verify(sTestAnimation).startAnimation(eq(dimLayer), eq(mTransaction), + anyInt(), any(SurfaceAnimator.OnAnimationFinishedCallback.class)); + verify(mTransaction).setRelativeLayer(dimLayer, mChild.mControl, 1); + verify(mTransaction, lastCall()).setAlpha(dimLayer, alpha); + } + @Test + public void testDimAboveWithChildCreatesSurfaceAboveChild_Legacy() { + assumeFalse(Flags.dimmerRefactor()); final float alpha = 0.8f; - mDimmer.dimAbove(child, alpha); - SurfaceControl dimLayer = getDimLayer(); + mHost.addChild(mChild, 0); + mDimmer.dimAbove(mChild, alpha); + SurfaceControl dimLayer = mDimmer.getDimLayer(); assertNotNull("Dimmer should have created a surface", dimLayer); verify(mHost.getPendingTransaction()).setAlpha(dimLayer, alpha); - verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, 1); + verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, mChild.mControl, 1); } @Test - public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() { - TestWindowContainer child = new TestWindowContainer(mWm); - mHost.addChild(child, 0); + public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild_Smooth() { + assumeTrue(Flags.dimmerRefactor()); + final float alpha = 0.7f; + mHost.addChild(mChild, 0); + mDimmer.dimBelow(mChild, alpha, 50); + SurfaceControl dimLayer = mDimmer.getDimLayer(); - final float alpha = 0.8f; - mDimmer.dimBelow(child, alpha, 0); - SurfaceControl dimLayer = getDimLayer(); + assertNotNull("Dimmer should have created a surface", dimLayer); + + mDimmer.updateDims(mTransaction); + verify(sTestAnimation).startAnimation(eq(dimLayer), eq(mTransaction), + anyInt(), any(SurfaceAnimator.OnAnimationFinishedCallback.class)); + verify(mTransaction).setRelativeLayer(dimLayer, mChild.mControl, -1); + verify(mTransaction, lastCall()).setAlpha(dimLayer, alpha); + verify(mTransaction).setBackgroundBlurRadius(dimLayer, 50); + } + + @Test + public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild_Legacy() { + assumeFalse(Flags.dimmerRefactor()); + final float alpha = 0.7f; + mHost.addChild(mChild, 0); + mDimmer.dimBelow(mChild, alpha, 50); + SurfaceControl dimLayer = mDimmer.getDimLayer(); assertNotNull("Dimmer should have created a surface", dimLayer); verify(mHost.getPendingTransaction()).setAlpha(dimLayer, alpha); - verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, -1); + verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, mChild.mControl, -1); } @Test - public void testDimBelowWithChildSurfaceDestroyedWhenReset() { - TestWindowContainer child = new TestWindowContainer(mWm); - mHost.addChild(child, 0); + public void testDimBelowWithChildSurfaceDestroyedWhenReset_Smooth() { + assumeTrue(Flags.dimmerRefactor()); + mHost.addChild(mChild, 0); + + final float alpha = 0.8f; + // Dim once + mDimmer.dimBelow(mChild, alpha, 0); + SurfaceControl dimLayer = mDimmer.getDimLayer(); + mDimmer.updateDims(mTransaction); + // Reset, and don't dim + mDimmer.resetDimStates(); + mDimmer.updateDims(mTransaction); + verify(mTransaction).show(dimLayer); + verify(mTransaction).remove(dimLayer); + } + + @Test + public void testDimBelowWithChildSurfaceDestroyedWhenReset_Legacy() { + assumeFalse(Flags.dimmerRefactor()); + mHost.addChild(mChild, 0); final float alpha = 0.8f; - mDimmer.dimAbove(child, alpha); - SurfaceControl dimLayer = getDimLayer(); + mDimmer.dimAbove(mChild, alpha); + SurfaceControl dimLayer = mDimmer.getDimLayer(); mDimmer.resetDimStates(); mDimmer.updateDims(mTransaction); - verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any( - SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), + verify(sSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), + any(SurfaceControl.Transaction.class), any(AnimationAdapter.class), + anyBoolean(), eq(ANIMATION_TYPE_DIMMER)); verify(mHost.getPendingTransaction()).remove(dimLayer); } @Test public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() { - TestWindowContainer child = new TestWindowContainer(mWm); - mHost.addChild(child, 0); + mHost.addChild(mChild, 0); final float alpha = 0.8f; - mDimmer.dimAbove(child, alpha); - SurfaceControl dimLayer = getDimLayer(); + // Dim once + mDimmer.dimBelow(mChild, alpha, 0); + SurfaceControl dimLayer = mDimmer.getDimLayer(); + mDimmer.updateDims(mTransaction); + // Reset and dim again mDimmer.resetDimStates(); - mDimmer.dimAbove(child, alpha); - + mDimmer.dimAbove(mChild, alpha); mDimmer.updateDims(mTransaction); verify(mTransaction).show(dimLayer); verify(mTransaction, never()).remove(dimLayer); @@ -221,14 +292,12 @@ public class DimmerTests extends WindowTestsBase { @Test public void testDimUpdateWhileDimming() { - TestWindowContainer child = new TestWindowContainer(mWm); - mHost.addChild(child, 0); - + mHost.addChild(mChild, 0); final float alpha = 0.8f; - mDimmer.dimAbove(child, alpha); - final Rect bounds = mDimmer.mDimState.mDimBounds; + mDimmer.dimAbove(mChild, alpha); + final Rect bounds = mDimmer.getDimBounds(); - SurfaceControl dimLayer = getDimLayer(); + SurfaceControl dimLayer = mDimmer.getDimLayer(); bounds.set(0, 0, 10, 10); mDimmer.updateDims(mTransaction); verify(mTransaction).setWindowCrop(dimLayer, bounds.width(), bounds.height()); @@ -242,41 +311,56 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testRemoveDimImmediately() { - TestWindowContainer child = new TestWindowContainer(mWm); - mHost.addChild(child, 0); + public void testRemoveDimImmediately_Smooth() { + assumeTrue(Flags.dimmerRefactor()); + mHost.addChild(mChild, 0); + mDimmer.dimAbove(mChild, 1); + SurfaceControl dimLayer = mDimmer.getDimLayer(); + mDimmer.updateDims(mTransaction); + verify(mTransaction, times(1)).show(dimLayer); - mDimmer.dimAbove(child, 1); - SurfaceControl dimLayer = getDimLayer(); + reset(sTestAnimation); + mDimmer.dontAnimateExit(); + mDimmer.resetDimStates(); + mDimmer.updateDims(mTransaction); + verify(sTestAnimation, never()).startAnimation( + any(SurfaceControl.class), any(SurfaceControl.Transaction.class), + anyInt(), any(SurfaceAnimator.OnAnimationFinishedCallback.class)); + verify(mTransaction).remove(dimLayer); + } + + @Test + public void testRemoveDimImmediately_Legacy() { + assumeFalse(Flags.dimmerRefactor()); + mHost.addChild(mChild, 0); + mDimmer.dimAbove(mChild, 1); + SurfaceControl dimLayer = mDimmer.getDimLayer(); mDimmer.updateDims(mTransaction); verify(mTransaction, times(1)).show(dimLayer); - reset(mSurfaceAnimatorStarter); + reset(sSurfaceAnimatorStarter); mDimmer.dontAnimateExit(); mDimmer.resetDimStates(); mDimmer.updateDims(mTransaction); - verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any( - SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), + verify(sSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), + any(SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), eq(ANIMATION_TYPE_DIMMER)); verify(mTransaction).remove(dimLayer); } @Test - public void testDimmerWithBlurUpdatesTransaction() { + public void testDimmerWithBlurUpdatesTransaction_Legacy() { + assumeFalse(Flags.dimmerRefactor()); TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); final int blurRadius = 50; mDimmer.dimBelow(child, 0, blurRadius); - SurfaceControl dimLayer = getDimLayer(); + SurfaceControl dimLayer = mDimmer.getDimLayer(); assertNotNull("Dimmer should have created a surface", dimLayer); verify(mHost.getPendingTransaction()).setBackgroundBlurRadius(dimLayer, blurRadius); verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, -1); } - - private SurfaceControl getDimLayer() { - return mDimmer.mDimState.mDimLayer; - } } diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/LastCallVerifier.java b/services/tests/wmtests/src/com/android/server/wm/utils/LastCallVerifier.java new file mode 100644 index 000000000000..320d09444681 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/LastCallVerifier.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 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.utils; + +import org.mockito.internal.verification.VerificationModeFactory; +import org.mockito.internal.verification.api.VerificationData; +import org.mockito.invocation.Invocation; +import org.mockito.invocation.MatchableInvocation; +import org.mockito.verification.VerificationMode; + +import java.util.List; + +/** + * Verifier to check that the last call of a method received the expected argument + */ +public class LastCallVerifier implements VerificationMode { + + /** + * Allows comparing the expected invocation with the last invocation on the same method + */ + public static LastCallVerifier lastCall() { + return new LastCallVerifier(); + } + + @Override + public void verify(VerificationData data) { + List<Invocation> invocations = data.getAllInvocations(); + MatchableInvocation target = data.getTarget(); + for (int i = invocations.size() - 1; i >= 0; i--) { + final Invocation invocation = invocations.get(i); + if (target.hasSameMethod(invocation)) { + if (target.matches(invocation)) { + return; + } else { + throw new LastCallMismatch(target.getInvocation(), invocation, invocations); + } + } + } + throw new RuntimeException(target + " never invoked"); + } + + @Override + public VerificationMode description(String description) { + return VerificationModeFactory.description(this, description); + } + + static class LastCallMismatch extends RuntimeException { + LastCallMismatch( + Invocation expected, Invocation received, List<Invocation> allInvocations) { + super("Expected invocation " + expected + " but received " + received + + " as the last invocation.\nAll registered invocations:\n" + allInvocations); + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockAnimationAdapter.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockAnimationAdapter.java new file mode 100644 index 000000000000..1a66970a8dc2 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockAnimationAdapter.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 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.utils; + +import android.util.proto.ProtoOutputStream; +import android.view.SurfaceControl; + +import androidx.annotation.NonNull; + +import com.android.server.wm.AnimationAdapter; +import com.android.server.wm.SurfaceAnimator; + +import java.io.PrintWriter; + +/** + * An empty animation adapter which just executes the finish callback + */ +public class MockAnimationAdapter implements AnimationAdapter { + + @Override + public boolean getShowWallpaper() { + return false; + } + + @Override + public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, + int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { + // As the animation won't run, finish it immediately + finishCallback.onAnimationFinished(0, null); + } + + @Override + public void onAnimationCancelled(SurfaceControl animationLeash) {} + + @Override + public long getDurationHint() { + return 0; + } + + @Override + public long getStatusBarTransitionsStartTime() { + return 0; + } + + @Override + public void dump(PrintWriter pw, String prefix) {} + + @Override + public void dumpDebug(ProtoOutputStream proto) {} +} diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt index 241e69106718..f61cce666cca 100644 --- a/test-mock/api/current.txt +++ b/test-mock/api/current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android.test.mock { @Deprecated public class MockAccountManager { @@ -202,7 +200,7 @@ package android.test.mock { method @Deprecated public int checkPermission(String, String); method @Deprecated public int checkSignatures(String, String); method @Deprecated public int checkSignatures(int, int); - method public void clearInstantAppCookie(); + method @Deprecated public void clearInstantAppCookie(); method @Deprecated public void clearPackagePreferredActivities(String); method @Deprecated public String[] currentToCanonicalPackageNames(String[]); method @Deprecated public void extendVerificationTimeout(int, int, long); @@ -224,15 +222,15 @@ package android.test.mock { method @Deprecated public CharSequence getApplicationLabel(android.content.pm.ApplicationInfo); method @Deprecated public android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo); method @Deprecated public android.graphics.drawable.Drawable getApplicationLogo(String) throws android.content.pm.PackageManager.NameNotFoundException; - method public android.content.pm.ChangedPackages getChangedPackages(int); + method @Deprecated public android.content.pm.ChangedPackages getChangedPackages(int); method @Deprecated public int getComponentEnabledSetting(android.content.ComponentName); method @Deprecated public android.graphics.drawable.Drawable getDefaultActivityIcon(); method @Deprecated public android.graphics.drawable.Drawable getDrawable(String, int, android.content.pm.ApplicationInfo); method @Deprecated public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method @Deprecated public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method @Deprecated public String getInstallerPackageName(String); - method public byte[] getInstantAppCookie(); - method public int getInstantAppCookieMaxBytes(); + method @Deprecated public byte[] getInstantAppCookie(); + method @Deprecated public int getInstantAppCookieMaxBytes(); method @Deprecated public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; method @Deprecated public android.content.Intent getLaunchIntentForPackage(String); method @Deprecated public android.content.Intent getLeanbackLaunchIntentForPackage(String); @@ -241,7 +239,7 @@ package android.test.mock { method @Deprecated public int[] getPackageGids(String, int) throws android.content.pm.PackageManager.NameNotFoundException; method @Deprecated public android.content.pm.PackageInfo getPackageInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException; method @Deprecated public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException; - method public android.content.pm.PackageInstaller getPackageInstaller(); + method @Deprecated public android.content.pm.PackageInstaller getPackageInstaller(); method @Deprecated public int getPackageUid(String, int) throws android.content.pm.PackageManager.NameNotFoundException; method @Deprecated public String[] getPackagesForUid(int); method @Deprecated public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(String[], int); @@ -265,8 +263,8 @@ package android.test.mock { method @Deprecated public android.content.res.XmlResourceParser getXml(String, int, android.content.pm.ApplicationInfo); method @Deprecated public boolean hasSystemFeature(String); method @Deprecated public boolean hasSystemFeature(String, int); - method public boolean isInstantApp(); - method public boolean isInstantApp(String); + method @Deprecated public boolean isInstantApp(); + method @Deprecated public boolean isInstantApp(String); method @Deprecated public boolean isPermissionRevokedByPolicy(String, String); method @Deprecated public boolean isSafeMode(); method @Deprecated public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); @@ -283,11 +281,12 @@ package android.test.mock { method @Deprecated public android.content.pm.ProviderInfo resolveContentProvider(String, int); method @Deprecated public android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method @Deprecated public android.content.pm.ResolveInfo resolveServiceAsUser(android.content.Intent, int, int); - method public void setApplicationCategoryHint(String, int); + method @Deprecated public void setApplicationCategoryHint(String, int); method @Deprecated public void setApplicationEnabledSetting(String, int, int); method @Deprecated public void setComponentEnabledSetting(android.content.ComponentName, int, int); method @Deprecated public void setInstallerPackageName(String, String); - method public void updateInstantAppCookie(@NonNull byte[]); + method @Deprecated public boolean setInstantAppCookie(@NonNull byte[]); + method @Deprecated public void updateInstantAppCookie(@NonNull byte[]); method @Deprecated public void verifyPendingInstall(int, int); } diff --git a/test-mock/api/removed.txt b/test-mock/api/removed.txt index fa2fbd276e9a..0c800b6f82b5 100644 --- a/test-mock/api/removed.txt +++ b/test-mock/api/removed.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android.test.mock { public class MockContext extends android.content.Context { @@ -11,7 +9,7 @@ package android.test.mock { @Deprecated public class MockPackageManager extends android.content.pm.PackageManager { method @Deprecated public String getDefaultBrowserPackageName(int); method @Deprecated public boolean setDefaultBrowserPackageName(String, int); - method public boolean setInstantAppCookie(@NonNull byte[]); + method @Deprecated public boolean setInstantAppCookie(@NonNull byte[]); } } diff --git a/test-mock/api/system-current.txt b/test-mock/api/system-current.txt index 2b5132ecd14f..f35095743738 100644 --- a/test-mock/api/system-current.txt +++ b/test-mock/api/system-current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android.test.mock { public class MockContext extends android.content.Context { @@ -11,30 +9,30 @@ package android.test.mock { } @Deprecated public class MockPackageManager extends android.content.pm.PackageManager { - method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); - method public boolean arePermissionsIndividuallyControlled(); + method @Deprecated public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); + method @Deprecated public boolean arePermissionsIndividuallyControlled(); method @Deprecated public java.util.List<android.content.IntentFilter> getAllIntentFilters(String); - method public String getDefaultBrowserPackageNameAsUser(int); - method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); - method public android.graphics.drawable.Drawable getInstantAppIcon(String); - method public android.content.ComponentName getInstantAppInstallerComponent(); - method public android.content.ComponentName getInstantAppResolverSettingsComponent(); - method public java.util.List<android.content.pm.InstantAppInfo> getInstantApps(); - method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String); - method public int getIntentVerificationStatusAsUser(String, int); - method public int getPermissionFlags(String, String, android.os.UserHandle); - method public void grantRuntimePermission(String, String, android.os.UserHandle); - method public int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException; - method public int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException; - method public void registerDexModule(String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback); - method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); - method public void revokeRuntimePermission(String, String, android.os.UserHandle); - method public boolean setDefaultBrowserPackageNameAsUser(String, int); + method @Deprecated public String getDefaultBrowserPackageNameAsUser(int); + method @Deprecated public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); + method @Deprecated public android.graphics.drawable.Drawable getInstantAppIcon(String); + method @Deprecated public android.content.ComponentName getInstantAppInstallerComponent(); + method @Deprecated public android.content.ComponentName getInstantAppResolverSettingsComponent(); + method @Deprecated public java.util.List<android.content.pm.InstantAppInfo> getInstantApps(); + method @Deprecated public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String); + method @Deprecated public int getIntentVerificationStatusAsUser(String, int); + method @Deprecated public int getPermissionFlags(String, String, android.os.UserHandle); + method @Deprecated public void grantRuntimePermission(String, String, android.os.UserHandle); + method @Deprecated public int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException; + method @Deprecated public int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method @Deprecated public void registerDexModule(String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback); + method @Deprecated public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); + method @Deprecated public void revokeRuntimePermission(String, String, android.os.UserHandle); + method @Deprecated public boolean setDefaultBrowserPackageNameAsUser(String, int); method public String[] setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, String); - method public void setUpdateAvailable(String, boolean); - method public boolean updateIntentVerificationStatusAsUser(String, int, int); - method public void updatePermissionFlags(String, String, int, int, android.os.UserHandle); - method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>); + method @Deprecated public void setUpdateAvailable(String, boolean); + method @Deprecated public boolean updateIntentVerificationStatusAsUser(String, int, int); + method @Deprecated public void updatePermissionFlags(String, String, int, int, android.os.UserHandle); + method @Deprecated public void verifyIntentFilter(int, int, java.util.List<java.lang.String>); } } diff --git a/test-mock/api/system-removed.txt b/test-mock/api/system-removed.txt index 14191ebcb080..d802177e249b 100644 --- a/test-mock/api/system-removed.txt +++ b/test-mock/api/system-removed.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt index 1752edcd469e..9ed010881067 100644 --- a/test-mock/api/test-current.txt +++ b/test-mock/api/test-current.txt @@ -1,6 +1,4 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 package android.test.mock { public class MockContext extends android.content.Context { @@ -8,13 +6,13 @@ package android.test.mock { } @Deprecated public class MockPackageManager extends android.content.pm.PackageManager { - method public void addCrossProfileIntentFilter(android.content.IntentFilter, int, int, int); - method public void clearCrossProfileIntentFilters(int); - method public int getInstallReason(String, android.os.UserHandle); - method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int); - method public String[] getNamesForUids(int[]); - method @NonNull public String getServicesSystemSharedLibraryPackageName(); - method @NonNull public String getSharedSystemSharedLibraryPackageName(); + method @Deprecated public void addCrossProfileIntentFilter(android.content.IntentFilter, int, int, int); + method @Deprecated public void clearCrossProfileIntentFilters(int); + method @Deprecated public int getInstallReason(String, android.os.UserHandle); + method @Deprecated public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int); + method @Deprecated public String[] getNamesForUids(int[]); + method @Deprecated @NonNull public String getServicesSystemSharedLibraryPackageName(); + method @Deprecated @NonNull public String getSharedSystemSharedLibraryPackageName(); } } diff --git a/test-mock/api/test-removed.txt b/test-mock/api/test-removed.txt index 14191ebcb080..d802177e249b 100644 --- a/test-mock/api/test-removed.txt +++ b/test-mock/api/test-removed.txt @@ -1,3 +1 @@ // Signature format: 2.0 -// - add-additional-overrides=no -// - migrating=Migration in progress see b/299366704 |