diff options
324 files changed, 7365 insertions, 3176 deletions
diff --git a/Android.bp b/Android.bp index 4219d3650ea6..0acc3d69a597 100644 --- a/Android.bp +++ b/Android.bp @@ -384,6 +384,7 @@ java_defaults { "core/java/android/view/IRecentsAnimationRunner.aidl", "core/java/android/view/IRemoteAnimationFinishedCallback.aidl", "core/java/android/view/IRotationWatcher.aidl", + "core/java/android/view/ISystemGestureExclusionListener.aidl", "core/java/android/view/IWallpaperVisibilityListener.aidl", "core/java/android/view/IWindow.aidl", "core/java/android/view/IWindowFocusObserver.aidl", @@ -753,10 +754,6 @@ java_defaults { "android.hardware.radio-V1.2-java", "android.hardware.radio-V1.3-java", "android.hardware.radio-V1.4-java", - "android.hardware.radio.config-V1.0-java", - "android.hardware.radio.config-V1.1-java", - "android.hardware.radio.config-V1.2-java", - "android.hardware.radio.deprecated-V1.0-java", "android.hardware.thermal-V1.0-java-constants", "android.hardware.thermal-V1.0-java", "android.hardware.thermal-V1.1-java", @@ -772,7 +769,6 @@ java_defaults { "android.hardware.vibrator-V1.3-java", "android.hardware.wifi-V1.0-java-constants", "networkstack-aidl-framework-java", - "netd_aidl_parcelables-java", "devicepolicyprotosnano", ], @@ -912,6 +908,9 @@ aidl_interface { "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl", "core/java/android/net/ip/IIpClient.aidl", "core/java/android/net/ip/IIpClientCallbacks.aidl", + "core/java/android/net/IIpMemoryStore.aidl", + "core/java/android/net/IIpMemoryStoreCallbacks.aidl", + "core/java/android/net/ipmemorystore/**/*.aidl", ], backend: { ndk: { @@ -925,13 +924,21 @@ aidl_interface { } aidl_interface { - name: "networkstack-aidl-framework", + name: "ipmemorystore-aidl-interfaces", local_include_dir: "core/java", srcs: [ - "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl", "core/java/android/net/IIpMemoryStore.aidl", + "core/java/android/net/IIpMemoryStoreCallbacks.aidl", "core/java/android/net/ipmemorystore/**/*.aidl", ], +} + +aidl_interface { + name: "networkstack-aidl-framework", + local_include_dir: "core/java", + srcs: [ + "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl", + ], api_dir: "aidl/networkstack", backend: { java: { @@ -941,18 +948,25 @@ aidl_interface { } filegroup { - name: "framework-networkstack-shared-srcs", + name: "framework-annotations", srcs: [ - // TODO: remove these annotations as soon as we can use andoid.support.annotations.* "core/java/android/annotation/NonNull.java", "core/java/android/annotation/Nullable.java", "core/java/android/annotation/IntDef.java", "core/java/android/annotation/IntRange.java", "core/java/android/annotation/UnsupportedAppUsage.java", - "core/java/android/net/DhcpResults.java", - "core/java/android/util/LocalLog.java", "core/java/com/android/internal/annotations/GuardedBy.java", "core/java/com/android/internal/annotations/VisibleForTesting.java", + ] +} + +filegroup { + name: "framework-networkstack-shared-srcs", + srcs: [ + // TODO: remove these annotations as soon as we can use andoid.support.annotations.* + ":framework-annotations", + "core/java/android/net/DhcpResults.java", + "core/java/android/util/LocalLog.java", "core/java/com/android/internal/util/HexDump.java", "core/java/com/android/internal/util/IndentingPrintWriter.java", "core/java/com/android/internal/util/IState.java", @@ -1807,4 +1821,4 @@ aidl_mapping { name: "framework-aidl-mappings", srcs: [":framework-defaults"], output: "framework-aidl-mappings.txt" -}
\ No newline at end of file +} diff --git a/api/current.txt b/api/current.txt index dcaa28ba8c64..34c2c2942ded 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5429,7 +5429,7 @@ package android.app { method @NonNull public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput); method @NonNull public android.app.Notification.Action build(); method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); - method public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); method @NonNull public android.app.Notification.Action.Builder setContextual(boolean); method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int); @@ -6623,7 +6623,7 @@ package android.app.admin { method @Nullable public String[] getAccountTypesWithManagementDisabled(); method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins(); method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName); - method @Nullable public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName); + method @Nullable public java.util.Set<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName); method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName); method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String); method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName); @@ -6736,7 +6736,7 @@ package android.app.admin { method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean); method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>); method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException; - method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException; + method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.Set<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean); method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle); method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -11051,6 +11051,7 @@ package android.content.pm { method public void dump(android.util.Printer, String); method public static CharSequence getCategoryTitle(android.content.Context, int); method public boolean isProfileableByShell(); + method public boolean isResourceOverlay(); method public boolean isVirtualPreload(); method public CharSequence loadDescription(android.content.pm.PackageManager); field public static final int CATEGORY_AUDIO = 1; // 0x1 @@ -11676,7 +11677,6 @@ package android.content.pm { field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; field public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint"; - field public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable"; field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management"; field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad"; field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors"; @@ -12016,7 +12016,7 @@ package android.content.pm { method @NonNull public android.content.pm.ShortcutInfo.Builder setIntents(@NonNull android.content.Intent[]); method @NonNull public android.content.pm.ShortcutInfo.Builder setLocusId(@NonNull android.content.LocusId); method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLabel(@NonNull CharSequence); - method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived(); + method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived(boolean); method @NonNull public android.content.pm.ShortcutInfo.Builder setPerson(@NonNull android.app.Person); method @NonNull public android.content.pm.ShortcutInfo.Builder setPersons(@NonNull android.app.Person[]); method @NonNull public android.content.pm.ShortcutInfo.Builder setRank(int); @@ -23294,6 +23294,7 @@ package android.media { field public static final String ACTION_MICROPHONE_MUTE_CHANGED = "android.media.action.MICROPHONE_MUTE_CHANGED"; field @Deprecated public static final String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED"; field public static final String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED"; + field public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = "android.media.action.SPEAKERPHONE_STATE_CHANGED"; field public static final int ADJUST_LOWER = -1; // 0xffffffff field public static final int ADJUST_MUTE = -100; // 0xffffff9c field public static final int ADJUST_RAISE = 1; // 0x1 @@ -25082,6 +25083,7 @@ package android.media { field public static final String KEY_LANGUAGE = "language"; field public static final String KEY_LATENCY = "latency"; field public static final String KEY_LEVEL = "level"; + field public static final String KEY_MAX_BFRAMES = "max-bframes"; field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder"; field public static final String KEY_MAX_HEIGHT = "max-height"; field public static final String KEY_MAX_INPUT_SIZE = "max-input-size"; @@ -25698,14 +25700,14 @@ package android.media { public static class MediaPlayer2.DrmEventCallback { ctor public MediaPlayer2.DrmEventCallback(); method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm); - method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo); - method public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest); + method @Nullable public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo); + method @NonNull public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest); method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]); } public static final class MediaPlayer2.DrmInfo { - method public java.util.Map<java.util.UUID,byte[]> getPssh(); - method public java.util.List<java.util.UUID> getSupportedSchemes(); + method @NonNull public java.util.Map<java.util.UUID,byte[]> getPssh(); + method @NonNull public java.util.List<java.util.UUID> getSupportedSchemes(); } public static final class MediaPlayer2.DrmPreparationInfo { @@ -25713,13 +25715,13 @@ package android.media { public static final class MediaPlayer2.DrmPreparationInfo.Builder { ctor public MediaPlayer2.DrmPreparationInfo.Builder(); - method public android.media.MediaPlayer2.DrmPreparationInfo build(); - method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]); - method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]); - method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int); - method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String); - method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>); - method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID); + method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo build(); + method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]); + method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]); + method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int); + method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String); + method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>); + method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID); } public static class MediaPlayer2.EventCallback { @@ -25750,7 +25752,7 @@ package android.media { } public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException { - ctor public MediaPlayer2.NoDrmSchemeException(String); + ctor public MediaPlayer2.NoDrmSchemeException(@Nullable String); } public static class MediaPlayer2.TrackInfo { @@ -28757,10 +28759,9 @@ package android.net { } public final class DnsResolver { - method public static android.net.DnsResolver getInstance(); - method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException; - method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException; - method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.InetAddressAnswerListener) throws android.system.ErrnoException; + method @NonNull public static android.net.DnsResolver getInstance(); + method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>); + method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>); field public static final int CLASS_IN = 1; // 0x1 field public static final int FLAG_EMPTY = 0; // 0x0 field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4 @@ -28770,12 +28771,23 @@ package android.net { field public static final int TYPE_AAAA = 28; // 0x1c } - public static interface DnsResolver.InetAddressAnswerListener { - method public void onAnswer(@NonNull java.util.List<java.net.InetAddress>); + public abstract static class DnsResolver.AnswerCallback<T> { + ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>); + method public abstract void onAnswer(@NonNull T); + method public abstract void onParseException(@NonNull android.net.ParseException); + method public abstract void onQueryException(@NonNull android.system.ErrnoException); + } + + public static interface DnsResolver.AnswerParser<T> { + method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException; } - public static interface DnsResolver.RawAnswerListener { - method public void onAnswer(@Nullable byte[]); + public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> { + ctor public DnsResolver.InetAddressAnswerCallback(); + } + + public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> { + ctor public DnsResolver.RawAnswerCallback(); } public class InetAddresses { @@ -29090,6 +29102,8 @@ package android.net { } public class ParseException extends java.lang.RuntimeException { + ctor public ParseException(@NonNull String); + ctor public ParseException(@NonNull String, @NonNull Throwable); field public String response; } @@ -45049,7 +45063,6 @@ package android.telephony { method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setMetered(boolean, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]); method public void setSubscriptionOverrideCongested(int, boolean, long); @@ -45287,7 +45300,7 @@ package android.telephony { field public static final int PHONE_TYPE_GSM = 1; // 0x1 field public static final int PHONE_TYPE_NONE = 0; // 0x0 field public static final int PHONE_TYPE_SIP = 3; // 0x3 - field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2 + field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2 field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0 field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1 field public static final int SIM_STATE_ABSENT = 1; // 0x1 @@ -50431,6 +50444,7 @@ package android.view { method protected float getLeftFadingEdgeStrength(); method protected int getLeftPaddingOffset(); method public final boolean getLocalVisibleRect(android.graphics.Rect); + method public void getLocationInSurface(@NonNull @Size(2) int[]); method public void getLocationInWindow(@Size(2) int[]); method public void getLocationOnScreen(@Size(2) int[]); method public android.graphics.Matrix getMatrix(); @@ -51944,6 +51958,7 @@ package android.view { method @NonNull public android.view.WindowInsets consumeStableInsets(); method @NonNull public android.view.WindowInsets consumeSystemWindowInsets(); method @Nullable public android.view.DisplayCutout getDisplayCutout(); + method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets(); method public int getStableInsetBottom(); method public int getStableInsetLeft(); method public int getStableInsetRight(); @@ -51955,6 +51970,7 @@ package android.view { method public int getSystemWindowInsetRight(); method public int getSystemWindowInsetTop(); method @NonNull public android.graphics.Insets getSystemWindowInsets(); + method @NonNull public android.graphics.Insets getTappableElementInsets(); method public boolean hasInsets(); method public boolean hasStableInsets(); method public boolean hasSystemWindowInsets(); @@ -51970,9 +51986,11 @@ package android.view { ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets); method @NonNull public android.view.WindowInsets build(); method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout); + method @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets); method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets); method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets); method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets); + method @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets); } public interface WindowManager extends android.view.ViewManager { @@ -53017,7 +53035,7 @@ package android.view.contentcapture { method public int describeContents(); method @NonNull public static android.view.contentcapture.ContentCaptureContext forLocusId(@NonNull String); method @Nullable public android.os.Bundle getExtras(); - method @NonNull public android.content.LocusId getLocusId(); + method @Nullable public android.content.LocusId getLocusId(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureContext> CREATOR; } diff --git a/api/removed.txt b/api/removed.txt index 4fe0ed9b5313..fa07094e6b84 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -314,17 +314,11 @@ package android.media.tv { package android.net { public class ConnectivityManager { - method @Deprecated public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler); method @Deprecated public boolean requestRouteToHost(int, int); method @Deprecated public int startUsingNetworkFeature(int, String); method @Deprecated public int stopUsingNetworkFeature(int, String); } - @Deprecated public abstract static class ConnectivityManager.TetheringEntitlementValueListener { - ctor public ConnectivityManager.TetheringEntitlementValueListener(); - method public void onEntitlementResult(int); - } - @Deprecated public class NetworkBadging { method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme); field public static final int BADGING_4K = 30; // 0x1e diff --git a/api/system-current.txt b/api/system-current.txt index 27241330f2ff..220a79c7d68f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -186,6 +186,7 @@ package android { field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"; field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; + field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS"; field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED"; field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE"; field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"; @@ -665,7 +666,6 @@ package android.app.admin { method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser(); method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException; - method @Nullable @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS, conditional=true) public android.content.ComponentName getProfileOwnerAsUser(@NonNull android.os.UserHandle); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException; method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState(); method public boolean isDeviceManaged(); @@ -1479,6 +1479,7 @@ package android.content.om { } public class OverlayManager { + method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle); method public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@Nullable String, int); method public boolean setEnabled(@Nullable String, boolean, int); method public boolean setEnabledExclusiveInCategory(@Nullable String, int); @@ -1837,9 +1838,9 @@ package android.content.rollback { } public final class RollbackManager { - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks(); field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS"; field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE"; field public static final int STATUS_FAILURE = 1; // 0x1 @@ -4282,11 +4283,14 @@ package android.net { package android.net.apf { - public class ApfCapabilities { + public final class ApfCapabilities implements android.os.Parcelable { ctor public ApfCapabilities(int, int, int); + method public int describeContents(); method public static boolean getApfDrop8023Frames(android.content.Context); method public static int[] getApfEthTypeBlackList(android.content.Context); method public boolean hasDataAccess(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR; field public final int apfPacketFormat; field public final int apfVersionSupported; field public final int maximumApfProgramSize; @@ -4484,16 +4488,16 @@ package android.net.metrics { package android.net.util { - public class SocketUtils { + public final class SocketUtils { method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException; method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException; method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException; method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException; method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException; method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException; - method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); - method public static java.net.SocketAddress makePacketSocketAddress(short, int); - method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]); + method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); + method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int); + method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]); method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException; } @@ -4934,6 +4938,10 @@ package android.net.wifi { public final class WifiUsabilityStatsEntry implements android.os.Parcelable { method public int describeContents(); + method public int getCellularDataNetworkType(); + method public int getCellularSignalStrengthDb(); + method public int getCellularSignalStrengthDbm(); + method public boolean getIsSameRegisteredCell(); method public int getLinkSpeedMbps(); method public int getProbeElapsedTimeSinceLastUpdateMillis(); method public int getProbeMcsRateSinceLastUpdate(); @@ -5616,6 +5624,7 @@ package android.os { method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(); + method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String); @@ -5860,6 +5869,7 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot"; + field public static final String NAMESPACE_APP_COMPAT = "app_compat"; field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service"; field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONNECTIVITY = "connectivity"; @@ -5870,9 +5880,13 @@ package android.provider { field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention"; field public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; field public static final String NAMESPACE_NETD_NATIVE = "netd_native"; + field public static final String NAMESPACE_ROLLBACK = "rollback"; + field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; field public static final String NAMESPACE_RUNTIME = "runtime"; field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native"; field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot"; + field public static final String NAMESPACE_SCHEDULER = "scheduler"; + field public static final String NAMESPACE_STORAGE = "storage"; field public static final String NAMESPACE_SYSTEMUI = "systemui"; field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier"; } @@ -5901,23 +5915,6 @@ package android.provider { method @Nullable public String getString(@NonNull String, @Nullable String); } - public static interface DeviceConfig.Rollback { - field public static final String BOOT_NAMESPACE = "rollback_boot"; - field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout"; - field public static final String NAMESPACE = "rollback"; - field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis"; - } - - public static interface DeviceConfig.Scheduler { - field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection"; - field public static final String NAMESPACE = "scheduler"; - } - - public static interface DeviceConfig.Storage { - field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; - field public static final String NAMESPACE = "storage"; - } - public static interface DeviceConfig.Telephony { field public static final String NAMESPACE = "telephony"; field public static final String RAMPING_RINGER_DURATION = "ramping_ringer_duration"; @@ -6055,6 +6052,7 @@ package android.provider { field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS"; field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS"; + field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS"; field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE"; field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; } @@ -6118,6 +6116,7 @@ package android.provider { field public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode"; field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications"; field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications"; + field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages"; field public static final String USER_SETUP_COMPLETE = "user_setup_complete"; field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa @@ -6428,6 +6427,7 @@ package android.service.contentcapture { method public int getEventType(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR; + field public static final int TYPE_ACTIVITY_DESTROYED = 24; // 0x18 field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2 field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1 field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17 @@ -6446,6 +6446,7 @@ package android.service.contentcapture { method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; + field public static final String SERVICE_META_DATA = "android.content_capture"; } public final class SnapshotData implements android.os.Parcelable { @@ -7236,7 +7237,6 @@ package android.telephony { field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828 field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850 - field public static final int ACCESS_PROBE_LIMIT_REACHED = 2079; // 0x81f field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30 field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f @@ -7351,9 +7351,7 @@ package android.telephony { field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e field public static final int INVALID_SIM_STATE = 2224; // 0x8b0 field public static final int INVALID_TRANSACTION_ID = 81; // 0x51 - field public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 2052; // 0x804 field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff - field public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 2053; // 0x805 field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77 field public static final int IP_VERSION_MISMATCH = 2055; // 0x807 @@ -7372,6 +7370,10 @@ package android.telephony { field public static final int MAC_FAILURE = 2183; // 0x887 field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876 + field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f + field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804 + field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805 + field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61 field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802 @@ -7480,7 +7482,6 @@ package android.telephony { field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5 field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8 field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9 - field public static final int PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6 field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7 field public static final int PPP_TIMEOUT = 2228; // 0x8b4 @@ -7681,15 +7682,14 @@ package android.telephony { field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming"; } - public class NetworkRegistrationInfo implements android.os.Parcelable { - ctor public NetworkRegistrationInfo(int, int, int, int, int, boolean, @NonNull int[], @Nullable android.telephony.CellIdentity); + public final class NetworkRegistrationInfo implements android.os.Parcelable { method public int describeContents(); method public int getAccessNetworkTechnology(); - method @NonNull public int[] getAvailableServices(); + method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); method @Nullable public android.telephony.CellIdentity getCellIdentity(); method @Nullable public android.telephony.DataSpecificRegistrationStates getDataSpecificStates(); method public int getDomain(); - method public int getRegState(); + method public int getRegistrationState(); method public int getRejectCause(); method public int getRoamingType(); method public int getTransportType(); @@ -7699,31 +7699,30 @@ package android.telephony { field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR; field public static final int DOMAIN_CS = 1; // 0x1 field public static final int DOMAIN_PS = 2; // 0x2 - field public static final int REG_STATE_DENIED = 3; // 0x3 - field public static final int REG_STATE_HOME = 1; // 0x1 - field public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0; // 0x0 - field public static final int REG_STATE_NOT_REG_SEARCHING = 2; // 0x2 - field public static final int REG_STATE_ROAMING = 5; // 0x5 - field public static final int REG_STATE_UNKNOWN = 4; // 0x4 + field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3 + field public static final int REGISTRATION_STATE_HOME = 1; // 0x1 + field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0 + field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2 + field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5 + field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4 field public static final int SERVICE_TYPE_DATA = 2; // 0x2 field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 field public static final int SERVICE_TYPE_SMS = 3; // 0x3 + field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 } - public static class NetworkRegistrationInfo.Builder { + public static final class NetworkRegistrationInfo.Builder { ctor public NetworkRegistrationInfo.Builder(); method @NonNull public android.telephony.NetworkRegistrationInfo build(); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAccessNetworkTechnology(int); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull int[]); + method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull java.util.List<java.lang.Integer>); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setNrStatus(int); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegState(int); + method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRoamingType(int); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int); } diff --git a/api/test-current.txt b/api/test-current.txt index 4ccfa1c06745..9e8b02ae63e8 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -14,6 +14,7 @@ package android { field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS"; field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; + field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS"; field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG"; field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE"; field public static final String WRITE_OBB = "android.permission.WRITE_OBB"; @@ -720,13 +721,14 @@ package android.content.rollback { } public final class RollbackManager { - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender); + method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks(); + method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void reloadPersistedData(); field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS"; field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE"; + field public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS = "rollback_lifetime_in_millis"; field public static final int STATUS_FAILURE = 1; // 0x1 field public static final int STATUS_FAILURE_INSTALL = 3; // 0x3 field public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; // 0x2 @@ -1305,11 +1307,14 @@ package android.net { package android.net.apf { - public class ApfCapabilities { + public final class ApfCapabilities implements android.os.Parcelable { ctor public ApfCapabilities(int, int, int); + method public int describeContents(); method public static boolean getApfDrop8023Frames(android.content.Context); method public static int[] getApfEthTypeBlackList(android.content.Context); method public boolean hasDataAccess(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR; field public final int apfPacketFormat; field public final int apfVersionSupported; field public final int maximumApfProgramSize; @@ -1507,16 +1512,16 @@ package android.net.metrics { package android.net.util { - public class SocketUtils { + public final class SocketUtils { method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException; method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException; method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException; method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException; method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException; method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException; - method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); - method public static java.net.SocketAddress makePacketSocketAddress(short, int); - method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]); + method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); + method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int); + method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]); method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException; } @@ -2067,6 +2072,8 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; + field public static final String NAMESPACE_ROLLBACK = "rollback"; + field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; } public static interface DeviceConfig.OnPropertiesChangedListener { @@ -2092,13 +2099,6 @@ package android.provider { method @Nullable public String getString(@NonNull String, @Nullable String); } - public static interface DeviceConfig.Rollback { - field public static final String BOOT_NAMESPACE = "rollback_boot"; - field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout"; - field public static final String NAMESPACE = "rollback"; - field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis"; - } - public final class MediaStore { method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; @@ -2394,6 +2394,7 @@ package android.service.contentcapture { method public int getEventType(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR; + field public static final int TYPE_ACTIVITY_DESTROYED = 24; // 0x18 field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2 field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1 field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17 @@ -2412,6 +2413,7 @@ package android.service.contentcapture { method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; + field public static final String SERVICE_META_DATA = "android.content_capture"; } public final class SnapshotData implements android.os.Parcelable { @@ -2548,7 +2550,8 @@ package android.telephony { method public int getCarrierIdListVersion(); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); - method public void setCarrierTestOverride(String, String, String, String, String, String, String); + method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); + method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String); field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 @@ -3175,19 +3178,19 @@ package android.view.inspector { @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) public @interface InspectableProperty { method public abstract int attributeId() default android.content.res.Resources.ID_NULL; - method public abstract android.view.inspector.InspectableProperty.EnumMap[] enumMapping() default {}; - method public abstract android.view.inspector.InspectableProperty.FlagMap[] flagMapping() default {}; + method public abstract android.view.inspector.InspectableProperty.EnumEntry[] enumMapping() default {}; + method public abstract android.view.inspector.InspectableProperty.FlagEntry[] flagMapping() default {}; method public abstract boolean hasAttributeId() default true; method public abstract String name() default ""; method public abstract android.view.inspector.InspectableProperty.ValueType valueType() default android.view.inspector.InspectableProperty.ValueType.INFERRED; } - @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumMap { + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumEntry { method public abstract String name(); method public abstract int value(); } - @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagMap { + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagEntry { method public abstract int mask() default 0; method public abstract String name(); method public abstract int target(); @@ -3216,7 +3219,7 @@ package android.widget { } public class DatePicker extends android.widget.FrameLayout { - method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode(); + method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode(); field public static final int MODE_CALENDAR = 2; // 0x2 field public static final int MODE_SPINNER = 1; // 0x1 } @@ -3252,7 +3255,7 @@ package android.widget { method public android.view.View getAmView(); method public android.view.View getHourView(); method public android.view.View getMinuteView(); - method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumMap(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode(); + method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumEntry(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode(); method public android.view.View getPmView(); field public static final int MODE_CLOCK = 2; // 0x2 field public static final int MODE_SPINNER = 1; // 0x1 diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h index dcc69b30743d..718e361b38ab 100644 --- a/cmds/idmap2/idmap2/Commands.h +++ b/cmds/idmap2/idmap2/Commands.h @@ -20,10 +20,12 @@ #include <string> #include <vector> -bool Create(const std::vector<std::string>& args, std::ostream& out_error); -bool Dump(const std::vector<std::string>& args, std::ostream& out_error); -bool Lookup(const std::vector<std::string>& args, std::ostream& out_error); -bool Scan(const std::vector<std::string>& args, std::ostream& out_error); -bool Verify(const std::vector<std::string>& args, std::ostream& out_error); +#include "idmap2/Result.h" + +android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::string>& args); +android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args); +android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args); +android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args); +android::idmap2::Result<android::idmap2::Unit> Verify(const std::vector<std::string>& args); #endif // IDMAP2_IDMAP2_COMMANDS_H_ diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp index c416fa123b73..fdbb21044176 100644 --- a/cmds/idmap2/idmap2/Create.cpp +++ b/cmds/idmap2/idmap2/Create.cpp @@ -33,14 +33,17 @@ using android::ApkAssets; using android::idmap2::BinaryStreamVisitor; using android::idmap2::CommandLineOptions; +using android::idmap2::Error; using android::idmap2::Idmap; using android::idmap2::PoliciesToBitmask; using android::idmap2::PolicyBitmask; using android::idmap2::PolicyFlags; +using android::idmap2::Result; +using android::idmap2::Unit; using android::idmap2::utils::kIdmapFilePermissionMask; using android::idmap2::utils::UidHasWriteAccessToPath; -bool Create(const std::vector<std::string>& args, std::ostream& out_error) { +Result<Unit> Create(const std::vector<std::string>& args) { SYSTRACE << "Create " << args; std::string target_apk_path; std::string overlay_apk_path; @@ -63,15 +66,14 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) { &policies) .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks", &ignore_overlayable); - if (!opts.Parse(args, out_error)) { - return false; + const auto opts_ok = opts.Parse(args); + if (!opts_ok) { + return opts_ok.GetError(); } const uid_t uid = getuid(); if (!UidHasWriteAccessToPath(uid, idmap_path)) { - out_error << "error: uid " << uid << " does not have write access to " << idmap_path - << std::endl; - return false; + return Error("uid %d does not have write access to %s", uid, idmap_path.c_str()); } PolicyBitmask fulfilled_policies = 0; @@ -79,8 +81,7 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) { if (conv_result) { fulfilled_policies |= *conv_result; } else { - out_error << "error: " << conv_result.GetErrorMessage() << std::endl; - return false; + return conv_result.GetError(); } if (fulfilled_policies == 0) { @@ -89,36 +90,33 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) { const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); if (!target_apk) { - out_error << "error: failed to load apk " << target_apk_path << std::endl; - return false; + return Error("failed to load apk %s", target_apk_path.c_str()); } const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); if (!overlay_apk) { - out_error << "error: failed to load apk " << overlay_apk_path << std::endl; - return false; + return Error("failed to load apk %s", overlay_apk_path.c_str()); } + std::stringstream stream; const std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, - fulfilled_policies, !ignore_overlayable, out_error); + fulfilled_policies, !ignore_overlayable, stream); if (!idmap) { - return false; + return Error("failed to create idmap: %s", stream.str().c_str()); } umask(kIdmapFilePermissionMask); std::ofstream fout(idmap_path); if (fout.fail()) { - out_error << "failed to open idmap path " << idmap_path << std::endl; - return false; + return Error("failed to open idmap path %s", idmap_path.c_str()); } BinaryStreamVisitor visitor(fout); idmap->accept(&visitor); fout.close(); if (fout.fail()) { - out_error << "failed to write to idmap path " << idmap_path << std::endl; - return false; + return Error("failed to write to idmap path %s", idmap_path.c_str()); } - return true; + return Unit{}; } diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp index 3947703fe8da..fd5822251188 100644 --- a/cmds/idmap2/idmap2/Dump.cpp +++ b/cmds/idmap2/idmap2/Dump.cpp @@ -17,6 +17,7 @@ #include <fstream> #include <iostream> #include <memory> +#include <sstream> #include <string> #include <vector> @@ -24,14 +25,18 @@ #include "idmap2/Idmap.h" #include "idmap2/PrettyPrintVisitor.h" #include "idmap2/RawPrintVisitor.h" +#include "idmap2/Result.h" #include "idmap2/SysTrace.h" using android::idmap2::CommandLineOptions; +using android::idmap2::Error; using android::idmap2::Idmap; using android::idmap2::PrettyPrintVisitor; using android::idmap2::RawPrintVisitor; +using android::idmap2::Result; +using android::idmap2::Unit; -bool Dump(const std::vector<std::string>& args, std::ostream& out_error) { +Result<Unit> Dump(const std::vector<std::string>& args) { SYSTRACE << "Dump " << args; std::string idmap_path; bool verbose; @@ -40,14 +45,16 @@ bool Dump(const std::vector<std::string>& args, std::ostream& out_error) { CommandLineOptions("idmap2 dump") .MandatoryOption("--idmap-path", "input: path to idmap file to pretty-print", &idmap_path) .OptionalFlag("--verbose", "annotate every byte of the idmap", &verbose); - if (!opts.Parse(args, out_error)) { - return false; + const auto opts_ok = opts.Parse(args); + if (!opts_ok) { + return opts_ok.GetError(); } + std::stringstream stream; std::ifstream fin(idmap_path); - const std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, out_error); + const std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, stream); fin.close(); if (!idmap) { - return false; + return Error("failed to load idmap: %s", stream.str().c_str()); } if (verbose) { @@ -58,5 +65,5 @@ bool Dump(const std::vector<std::string>& args, std::ostream& out_error) { idmap->accept(&visitor); } - return true; + return Unit{}; } diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp index 83a40efee3f3..677c6fa155dd 100644 --- a/cmds/idmap2/idmap2/Lookup.cpp +++ b/cmds/idmap2/idmap2/Lookup.cpp @@ -57,6 +57,7 @@ using android::idmap2::Error; using android::idmap2::IdmapHeader; using android::idmap2::ResourceId; using android::idmap2::Result; +using android::idmap2::Unit; using android::idmap2::Xml; using android::idmap2::ZipFile; using android::util::Utf16ToUtf8; @@ -157,7 +158,7 @@ Result<std::string> GetTargetPackageNameFromManifest(const std::string& apk_path } } // namespace -bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) { +Result<Unit> Lookup(const std::vector<std::string>& args) { SYSTRACE << "Lookup " << args; std::vector<std::string> idmap_paths; std::string config_str; @@ -172,14 +173,14 @@ bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) { "'[package:]type/name') to look up", &resid_str); - if (!opts.Parse(args, out_error)) { - return false; + const auto opts_ok = opts.Parse(args); + if (!opts_ok) { + return opts_ok.GetError(); } ConfigDescription config; if (!ConfigDescription::Parse(config_str, &config)) { - out_error << "error: failed to parse config" << std::endl; - return false; + return Error("failed to parse config"); } std::vector<std::unique_ptr<const ApkAssets>> apk_assets; @@ -191,39 +192,33 @@ bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) { auto idmap_header = IdmapHeader::FromBinaryStream(fin); fin.close(); if (!idmap_header) { - out_error << "error: failed to read idmap from " << idmap_path << std::endl; - return false; + return Error("failed to read idmap from %s", idmap_path.c_str()); } if (i == 0) { target_path = idmap_header->GetTargetPath().to_string(); auto target_apk = ApkAssets::Load(target_path); if (!target_apk) { - out_error << "error: failed to read target apk from " << target_path << std::endl; - return false; + return Error("failed to read target apk from %s", target_path.c_str()); } apk_assets.push_back(std::move(target_apk)); const Result<std::string> package_name = GetTargetPackageNameFromManifest(idmap_header->GetOverlayPath().to_string()); if (!package_name) { - out_error << "error: failed to parse android:targetPackage from overlay manifest" - << std::endl; - return false; + return Error("failed to parse android:targetPackage from overlay manifest"); } target_package_name = *package_name; } else if (target_path != idmap_header->GetTargetPath()) { - out_error << "error: different target APKs (expected target APK " << target_path << " but " - << idmap_path << " has target APK " << idmap_header->GetTargetPath() << ")" - << std::endl; - return false; + return Error("different target APKs (expected target APK %s but %s has target APK %s)", + target_path.c_str(), idmap_path.c_str(), + idmap_header->GetTargetPath().to_string().c_str()); } auto overlay_apk = ApkAssets::LoadOverlay(idmap_path); if (!overlay_apk) { - out_error << "error: failed to read overlay apk from " << idmap_header->GetOverlayPath() - << std::endl; - return false; + return Error("failed to read overlay apk from %s", + idmap_header->GetOverlayPath().to_string().c_str()); } apk_assets.push_back(std::move(overlay_apk)); } @@ -238,16 +233,14 @@ bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) { const Result<ResourceId> resid = ParseResReference(am, resid_str, target_package_name); if (!resid) { - out_error << "error: failed to parse resource ID" << std::endl; - return false; + return Error(resid.GetError(), "failed to parse resource ID"); } const Result<std::string> value = GetValue(am, *resid); if (!value) { - out_error << StringPrintf("error: resource 0x%08x not found", *resid) << std::endl; - return false; + return Error(value.GetError(), "resource 0x%08x not found", *resid); } std::cout << *value << std::endl; - return true; + return Unit{}; } diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp index a0ffccb26dfe..d8867fe8f497 100644 --- a/cmds/idmap2/idmap2/Main.cpp +++ b/cmds/idmap2/idmap2/Main.cpp @@ -24,14 +24,17 @@ #include <vector> #include "idmap2/CommandLineOptions.h" +#include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "Commands.h" using android::idmap2::CommandLineOptions; +using android::idmap2::Result; +using android::idmap2::Unit; using NameToFunctionMap = - std::map<std::string, std::function<bool(const std::vector<std::string>&, std::ostream&)>>; + std::map<std::string, std::function<Result<Unit>(const std::vector<std::string>&)>>; namespace { @@ -69,5 +72,10 @@ int main(int argc, char** argv) { PrintUsage(commands, std::cerr); return EXIT_FAILURE; } - return iter->second(*args, std::cerr) ? EXIT_SUCCESS : EXIT_FAILURE; + const auto result = iter->second(*args); + if (!result) { + std::cerr << "error: " << result.GetErrorMessage() << std::endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index e85f132c6072..24331af9fd6d 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -30,6 +30,7 @@ #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" #include "idmap2/ResourceUtils.h" +#include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" @@ -37,6 +38,7 @@ #include "Commands.h" using android::idmap2::CommandLineOptions; +using android::idmap2::Error; using android::idmap2::Idmap; using android::idmap2::kPolicyProduct; using android::idmap2::kPolicyPublic; @@ -45,6 +47,7 @@ using android::idmap2::kPolicyVendor; using android::idmap2::PolicyBitmask; using android::idmap2::PolicyFlags; using android::idmap2::Result; +using android::idmap2::Unit; using android::idmap2::utils::ExtractOverlayManifestInfo; using android::idmap2::utils::FindFiles; using android::idmap2::utils::OverlayManifestInfo; @@ -69,8 +72,8 @@ bool VendorIsQOrLater() { return version == "Q" || version == "q"; } -std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs, - bool recursive, std::ostream& out_error) { +Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs, + bool recursive) { SYSTRACE << "FindApkFiles " << dirs << " " << recursive; const auto predicate = [](unsigned char type, const std::string& path) -> bool { static constexpr size_t kExtLen = 4; // strlen(".apk") @@ -82,8 +85,7 @@ std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::st for (const auto& dir : dirs) { const auto apk_paths = FindFiles(dir, recursive, predicate); if (!apk_paths) { - out_error << "error: failed to open directory " << dir << std::endl; - return nullptr; + return Error("failed to open directory %s", dir.c_str()); } paths.insert(apk_paths->cbegin(), apk_paths->cend()); } @@ -110,7 +112,7 @@ std::vector<std::string> PoliciesForPath(const std::string& apk_path) { } // namespace -bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { +Result<Unit> Scan(const std::vector<std::string>& args) { SYSTRACE << "Scan " << args; std::vector<std::string> input_directories; std::string target_package_name; @@ -135,22 +137,22 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { "input: an overlayable policy this overlay fulfills " "(if none or supplied, the overlays will not have their policies overriden", &override_policies); - if (!opts.Parse(args, out_error)) { - return false; + const auto opts_ok = opts.Parse(args); + if (!opts_ok) { + return opts_ok.GetError(); } - const auto apk_paths = FindApkFiles(input_directories, recursive, out_error); + const auto apk_paths = FindApkFiles(input_directories, recursive); if (!apk_paths) { - return false; + return Error(apk_paths.GetError(), "failed to find apk files"); } std::vector<InputOverlay> interesting_apks; - for (const std::string& path : *apk_paths) { + for (const std::string& path : **apk_paths) { Result<OverlayManifestInfo> overlay_info = ExtractOverlayManifestInfo(path, /* assert_overlay */ false); if (!overlay_info) { - out_error << "error: " << overlay_info.GetErrorMessage() << std::endl; - return false; + return overlay_info.GetError(); } if (!overlay_info->is_static) { @@ -194,16 +196,13 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { std::stringstream stream; for (const auto& overlay : interesting_apks) { - // Create the idmap for the overlay if it currently does not exist or if it is not up to date. - std::stringstream dev_null; - std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path}; for (const std::string& policy : overlay.policies) { verify_args.emplace_back("--policy"); verify_args.emplace_back(policy); } - if (!Verify(std::vector<std::string>(verify_args), dev_null)) { + if (!Verify(std::vector<std::string>(verify_args))) { std::vector<std::string> create_args = {"--target-apk-path", target_apk_path, "--overlay-apk-path", overlay.apk_path, "--idmap-path", overlay.idmap_path}; @@ -216,8 +215,9 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { create_args.emplace_back(policy); } - if (!Create(create_args, out_error)) { - return false; + const auto create_ok = Create(create_args); + if (!create_ok) { + return Error(create_ok.GetError(), "failed to create idmap"); } } @@ -226,5 +226,5 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { std::cout << stream.str(); - return true; + return Unit{}; } diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/Verify.cpp index d8fe7aa0ed99..9cb67b33e6cf 100644 --- a/cmds/idmap2/idmap2/Verify.cpp +++ b/cmds/idmap2/idmap2/Verify.cpp @@ -21,29 +21,39 @@ #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" +#include "idmap2/Result.h" #include "idmap2/SysTrace.h" using android::idmap2::CommandLineOptions; +using android::idmap2::Error; using android::idmap2::IdmapHeader; +using android::idmap2::Result; +using android::idmap2::Unit; -bool Verify(const std::vector<std::string>& args, std::ostream& out_error) { +Result<Unit> Verify(const std::vector<std::string>& args) { SYSTRACE << "Verify " << args; std::string idmap_path; const CommandLineOptions opts = CommandLineOptions("idmap2 verify") .MandatoryOption("--idmap-path", "input: path to idmap file to verify", &idmap_path); - if (!opts.Parse(args, out_error)) { - return false; + + const auto opts_ok = opts.Parse(args); + if (!opts_ok) { + return opts_ok.GetError(); } std::ifstream fin(idmap_path); const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin); fin.close(); if (!header) { - out_error << "error: failed to parse idmap header" << std::endl; - return false; + return Error("failed to parse idmap header"); + } + + const auto header_ok = header->IsUpToDate(); + if (!header_ok) { + return Error(header_ok.GetError(), "idmap not up to date"); } - return header->IsUpToDate(out_error); + return Unit{}; } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index fa944143e408..e03a9cc1032e 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -104,8 +104,7 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path, std::ifstream fin(idmap_path); const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin); fin.close(); - std::stringstream dev_null; - *_aidl_return = header && header->IsUpToDate(dev_null); + *_aidl_return = header && header->IsUpToDate(); // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h index 6db6bf9ea8ad..52ac8181da02 100644 --- a/cmds/idmap2/include/idmap2/CommandLineOptions.h +++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h @@ -23,6 +23,8 @@ #include <string> #include <vector> +#include "idmap2/Result.h" + namespace android::idmap2 { /* @@ -46,7 +48,7 @@ class CommandLineOptions { std::string* value); CommandLineOptions& OptionalOption(const std::string& name, const std::string& description, std::vector<std::string>* value); - bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const; + Result<Unit> Parse(const std::vector<std::string>& argv) const; void Usage(std::ostream& out) const; private: diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index 1666dc8a3bbd..673d18d25907 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -115,7 +115,7 @@ class IdmapHeader { // Invariant: anytime the idmap data encoding is changed, the idmap version // field *must* be incremented. Because of this, we know that if the idmap // header is up-to-date the entire file is up-to-date. - bool IsUpToDate(std::ostream& out_error) const; + Result<Unit> IsUpToDate() const; void accept(Visitor* v) const; diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp index a49a607091a4..d5fd2ce38b11 100644 --- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp +++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp @@ -19,12 +19,14 @@ #include <iostream> #include <memory> #include <set> +#include <sstream> #include <string> #include <vector> #include "android-base/macros.h" #include "idmap2/CommandLineOptions.h" +#include "idmap2/Result.h" namespace android::idmap2 { @@ -77,7 +79,7 @@ CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name, return *this; } -bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const { +Result<Unit> CommandLineOptions::Parse(const std::vector<std::string>& argv) const { const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) { return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE; }); @@ -89,8 +91,9 @@ bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostrea for (size_t i = 0; i < argv_size; i++) { const std::string arg = argv[i]; if ("--help" == arg || "-h" == arg) { - Usage(outError); - return false; + std::stringstream stream; + Usage(stream); + return Error("%s", stream.str().c_str()); } bool match = false; for (const Option& opt : options_) { @@ -100,9 +103,9 @@ bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostrea if (opt.argument) { i++; if (i >= argv_size) { - outError << "error: " << opt.name << ": missing argument" << std::endl; - Usage(outError); - return false; + std::stringstream stream; + Usage(stream); + return Error("%s: missing argument\n%s", opt.name.c_str(), stream.str().c_str()); } } opt.action(argv[i]); @@ -111,20 +114,27 @@ bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostrea } } if (!match) { - outError << "error: " << arg << ": unknown option" << std::endl; - Usage(outError); - return false; + std::stringstream stream; + Usage(stream); + return Error("%s: unknown option\n%s", arg.c_str(), stream.str().c_str()); } } if (!mandatory_opts.empty()) { + std::stringstream stream; + bool separator = false; for (const auto& opt : mandatory_opts) { - outError << "error: " << opt << ": missing mandatory option" << std::endl; + if (separator) { + stream << ", "; + } + separator = true; + stream << opt << ": missing mandatory option"; } - Usage(outError); - return false; + stream << std::endl; + Usage(stream); + return Error("%s", stream.str().c_str()); } - return true; + return Unit{}; } void CommandLineOptions::Usage(std::ostream& out) const { diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index a7d180c90307..9afdd437491f 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -142,62 +142,46 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s return std::move(idmap_header); } -bool IdmapHeader::IsUpToDate(std::ostream& out_error) const { +Result<Unit> IdmapHeader::IsUpToDate() const { if (magic_ != kIdmapMagic) { - out_error << base::StringPrintf("error: bad magic: actual 0x%08x, expected 0x%08x", magic_, - kIdmapMagic) - << std::endl; - return false; + return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic); } if (version_ != kIdmapCurrentVersion) { - out_error << base::StringPrintf("error: bad version: actual 0x%08x, expected 0x%08x", version_, - kIdmapCurrentVersion) - << std::endl; - return false; + return Error("bad version: actual 0x%08x, expected 0x%08x", version_, kIdmapCurrentVersion); } const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_); if (!target_zip) { - out_error << "error: failed to open target " << target_path_ << std::endl; - return false; + return Error("failed to open target %s", GetTargetPath().to_string().c_str()); } Result<uint32_t> target_crc = GetCrc(*target_zip); if (!target_crc) { - out_error << "error: failed to get target crc" << std::endl; - return false; + return Error("failed to get target crc"); } if (target_crc_ != *target_crc) { - out_error << base::StringPrintf( - "error: bad target crc: idmap version 0x%08x, file system version 0x%08x", - target_crc_, *target_crc) - << std::endl; - return false; + return Error("bad target crc: idmap version 0x%08x, file system version 0x%08x", target_crc_, + *target_crc); } const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_); if (!overlay_zip) { - out_error << "error: failed to open overlay " << overlay_path_ << std::endl; - return false; + return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str()); } Result<uint32_t> overlay_crc = GetCrc(*overlay_zip); if (!overlay_crc) { - out_error << "error: failed to get overlay crc" << std::endl; - return false; + return Error("failed to get overlay crc"); } if (overlay_crc_ != *overlay_crc) { - out_error << base::StringPrintf( - "error: bad overlay crc: idmap version 0x%08x, file system version 0x%08x", - overlay_crc_, *overlay_crc) - << std::endl; - return false; + return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_, + *overlay_crc); } - return true; + return Unit{}; } std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) { @@ -452,7 +436,7 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets( continue; } - if (!enforce_overlayable) { + if (enforce_overlayable) { Result<Unit> success = CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid); if (!success) { diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp index 39f18d3336af..d567af64b16a 100644 --- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp +++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp @@ -46,14 +46,13 @@ TEST(CommandLineOptionsTests, Flag) { CommandLineOptions opts = CommandLineOptions("test").OptionalFlag("--foo", "", &foo).OptionalFlag("--bar", "", &bar); - std::ostream fakeStdErr(nullptr); - bool success = opts.Parse({"--foo", "--bar"}, fakeStdErr); + auto success = opts.Parse({"--foo", "--bar"}); ASSERT_TRUE(success); ASSERT_TRUE(foo); ASSERT_TRUE(bar); foo = bar = false; - success = opts.Parse({"--foo"}, fakeStdErr); + success = opts.Parse({"--foo"}); ASSERT_TRUE(success); ASSERT_TRUE(foo); ASSERT_FALSE(bar); @@ -65,21 +64,19 @@ TEST(CommandLineOptionsTests, MandatoryOption) { CommandLineOptions opts = CommandLineOptions("test") .MandatoryOption("--foo", "", &foo) .MandatoryOption("--bar", "", &bar); - std::ostream fakeStdErr(nullptr); - bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr); + auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}); ASSERT_TRUE(success); ASSERT_EQ(foo, "FOO"); ASSERT_EQ(bar, "BAR"); - success = opts.Parse({"--foo"}, fakeStdErr); + success = opts.Parse({"--foo"}); ASSERT_FALSE(success); } TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsButExpectedOnce) { std::string foo; CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &foo); - std::ostream fakeStdErr(nullptr); - bool success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"}, fakeStdErr); + auto success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"}); ASSERT_TRUE(success); ASSERT_EQ(foo, "SECOND"); } @@ -87,8 +84,7 @@ TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsButExpectedOnce) { TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsAndExpectedOnceOrMore) { std::vector<std::string> args; CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &args); - std::ostream fakeStdErr(nullptr); - bool success = opts.Parse({"--foo", "FOO", "--foo", "BAR"}, fakeStdErr); + auto success = opts.Parse({"--foo", "FOO", "--foo", "BAR"}); ASSERT_TRUE(success); ASSERT_EQ(args.size(), 2U); ASSERT_EQ(args[0], "FOO"); @@ -101,23 +97,22 @@ TEST(CommandLineOptionsTests, OptionalOption) { CommandLineOptions opts = CommandLineOptions("test") .OptionalOption("--foo", "", &foo) .OptionalOption("--bar", "", &bar); - std::ostream fakeStdErr(nullptr); - bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr); + auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}); ASSERT_TRUE(success); ASSERT_EQ(foo, "FOO"); ASSERT_EQ(bar, "BAR"); - success = opts.Parse({"--foo", "BAZ"}, fakeStdErr); + success = opts.Parse({"--foo", "BAZ"}); ASSERT_TRUE(success); ASSERT_EQ(foo, "BAZ"); - success = opts.Parse({"--foo"}, fakeStdErr); + success = opts.Parse({"--foo"}); ASSERT_FALSE(success); - success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr); + success = opts.Parse({"--foo", "--bar", "BAR"}); ASSERT_FALSE(success); - success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr); + success = opts.Parse({"--foo", "FOO", "--bar"}); ASSERT_FALSE(success); } @@ -127,8 +122,7 @@ TEST(CommandLineOptionsTests, OptionalOptionList) { CommandLineOptions opts = CommandLineOptions("test") .OptionalOption("--foo", "", &foo) .OptionalOption("--bar", "", &bar); - std::ostream fakeStdErr(nullptr); - bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr); + auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}); ASSERT_TRUE(success); ASSERT_EQ(foo.size(), 1U); ASSERT_EQ(foo[0], "FOO"); @@ -137,7 +131,7 @@ TEST(CommandLineOptionsTests, OptionalOptionList) { foo.clear(); bar.clear(); - success = opts.Parse({"--foo", "BAZ"}, fakeStdErr); + success = opts.Parse({"--foo", "BAZ"}); ASSERT_TRUE(success); ASSERT_EQ(foo.size(), 1U); ASSERT_EQ(foo[0], "BAZ"); @@ -145,8 +139,7 @@ TEST(CommandLineOptionsTests, OptionalOptionList) { foo.clear(); bar.clear(); - success = - opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr); + success = opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}); ASSERT_TRUE(success); ASSERT_EQ(foo.size(), 2U); ASSERT_EQ(foo[0], "BAZ"); @@ -157,17 +150,17 @@ TEST(CommandLineOptionsTests, OptionalOptionList) { foo.clear(); bar.clear(); - success = opts.Parse({"--foo"}, fakeStdErr); + success = opts.Parse({"--foo"}); ASSERT_FALSE(success); foo.clear(); bar.clear(); - success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr); + success = opts.Parse({"--foo", "--bar", "BAR"}); ASSERT_FALSE(success); foo.clear(); bar.clear(); - success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr); + success = opts.Parse({"--foo", "FOO", "--bar"}); ASSERT_FALSE(success); } @@ -179,14 +172,13 @@ TEST(CommandLineOptionsTests, CornerCases) { .MandatoryOption("--foo", "", &foo) .OptionalFlag("--baz", "", &baz) .OptionalOption("--bar", "", &bar); - std::ostream fakeStdErr(nullptr); - bool success = opts.Parse({"--unexpected"}, fakeStdErr); + auto success = opts.Parse({"--unexpected"}); ASSERT_FALSE(success); - success = opts.Parse({"--bar", "BAR"}, fakeStdErr); + success = opts.Parse({"--bar", "BAR"}); ASSERT_FALSE(success); - success = opts.Parse({"--baz", "--foo", "FOO"}, fakeStdErr); + success = opts.Parse({"--baz", "--foo", "FOO"}); ASSERT_TRUE(success); ASSERT_TRUE(baz); ASSERT_EQ(foo, "FOO"); diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 8d65428f134e..c20ae7b798a3 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -501,7 +501,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream); ASSERT_THAT(header, NotNull()); - ASSERT_TRUE(header->IsUpToDate(error)) << error.str(); + ASSERT_TRUE(header->IsUpToDate()); // magic: bytes (0x0, 0x03) std::string bad_magic_string(stream.str()); @@ -514,7 +514,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_magic_stream); ASSERT_THAT(bad_magic_header, NotNull()); ASSERT_NE(header->GetMagic(), bad_magic_header->GetMagic()); - ASSERT_FALSE(bad_magic_header->IsUpToDate(error)); + ASSERT_FALSE(bad_magic_header->IsUpToDate()); // version: bytes (0x4, 0x07) std::string bad_version_string(stream.str()); @@ -527,7 +527,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_version_stream); ASSERT_THAT(bad_version_header, NotNull()); ASSERT_NE(header->GetVersion(), bad_version_header->GetVersion()); - ASSERT_FALSE(bad_version_header->IsUpToDate(error)); + ASSERT_FALSE(bad_version_header->IsUpToDate()); // target crc: bytes (0x8, 0xb) std::string bad_target_crc_string(stream.str()); @@ -540,7 +540,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_target_crc_stream); ASSERT_THAT(bad_target_crc_header, NotNull()); ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc()); - ASSERT_FALSE(bad_target_crc_header->IsUpToDate(error)); + ASSERT_FALSE(bad_target_crc_header->IsUpToDate()); // overlay crc: bytes (0xc, 0xf) std::string bad_overlay_crc_string(stream.str()); @@ -553,7 +553,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_overlay_crc_stream); ASSERT_THAT(bad_overlay_crc_header, NotNull()); ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc()); - ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate(error)); + ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate()); // target path: bytes (0x10, 0x10f) std::string bad_target_path_string(stream.str()); @@ -563,7 +563,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_target_path_stream); ASSERT_THAT(bad_target_path_header, NotNull()); ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath()); - ASSERT_FALSE(bad_target_path_header->IsUpToDate(error)); + ASSERT_FALSE(bad_target_path_header->IsUpToDate()); // overlay path: bytes (0x110, 0x20f) std::string bad_overlay_path_string(stream.str()); @@ -573,7 +573,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_overlay_path_stream); ASSERT_THAT(bad_overlay_path_header, NotNull()); ASSERT_NE(header->GetOverlayPath(), bad_overlay_path_header->GetOverlayPath()); - ASSERT_FALSE(bad_overlay_path_header->IsUpToDate(error)); + ASSERT_FALSE(bad_overlay_path_header->IsUpToDate()); } class TestVisitor : public Visitor { diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 7a753aecc4cb..1dbbbc5595ba 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -310,7 +310,7 @@ message Atom { DangerousPermissionState dangerous_permission_state = 10050; TrainInfo train_info = 10051; TimeZoneDataInfo time_zone_data_info = 10052; - SDCardInfo sdcard_info = 10053; + ExternalStorageInfo external_storage_info = 10053; GpuStatsGlobalInfo gpu_stats_global_info = 10054; GpuStatsAppInfo gpu_stats_app_info = 10055; SystemIonHeapSize system_ion_heap_size = 10056; @@ -3311,25 +3311,27 @@ message BatteryCycleCount { } /** - * Logs that an SD card is mounted and information about it, its type (public or private) and the - * size in bytes. + * Logs that external storage is mounted and information about it, the storage type (sd card/usb/ + * others), its type (public or private) and the size in bytes. * Pulled from: * StatsCompanionService */ -message SDCardInfo { +message ExternalStorageInfo { - enum Type { + enum VolumeType { UNKNOWN = 0; - TYPE_PUBLIC = 1; - TYPE_PRIVATE = 2; - OTHERS = 3; + PUBLIC = 1; + PRIVATE = 2; + OTHER = 3; } - // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal. - optional Type type = 1; + // The type of external storage. + optional android.stats.storage.ExternalStorageType storage_type = 1; + // Type of the volume: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal. + optional VolumeType volume_type = 2; // Total size of the sd card in bytes. - optional int64 size_bytes = 2; + optional int64 size_bytes = 3; } /* diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index c7ae656920b8..2abfc2450a00 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -242,9 +242,9 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // TimeZoneDataInfo. {android::util::TIME_ZONE_DATA_INFO, {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}}, - // SDCardInfo - {android::util::SDCARD_INFO, - {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}}, + // ExternalStorageInfo + {android::util::EXTERNAL_STORAGE_INFO, + {.puller = new StatsCompanionServicePuller(android::util::EXTERNAL_STORAGE_INFO)}}, // GpuStatsGlobalInfo {android::util::GPU_STATS_GLOBAL_INFO, {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}}, diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index f6cfe4855070..e8d32932503b 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -340,4 +340,21 @@ public abstract class ActivityManagerInternal { * like persisting database etc. */ public abstract void prepareForPossibleShutdown(); + + /** + * Returns {@code true} if {@code uid} is running a foreground service of a specific + * {@code foregroundServiceType}. + */ + public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType); + + /** + * Registers the specified {@code processObserver} to be notified of future changes to + * process state. + */ + public abstract void registerProcessObserver(IProcessObserver processObserver); + + /** + * Unregisters the specified {@code processObserver}. + */ + public abstract void unregisterProcessObserver(IProcessObserver processObserver); } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index a2260625a0c2..7a0639eef8cc 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -3054,9 +3054,9 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public String getContentCaptureServicePackageName() { + public String getSystemCaptionsServicePackageName() { try { - return mPM.getContentCaptureServicePackageName(); + return mPM.getSystemCaptionsServicePackageName(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl index b436aa2bcd0f..7be3620f317b 100644 --- a/core/java/android/app/IProcessObserver.aidl +++ b/core/java/android/app/IProcessObserver.aidl @@ -19,5 +19,6 @@ package android.app; /** {@hide} */ oneway interface IProcessObserver { void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities); + void onForegroundServicesChanged(int pid, int uid, int serviceTypes); void onProcessDied(int pid, int uid); } diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 3ecb5870416f..bcd43a209e60 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -440,7 +440,7 @@ public class KeyguardManager { */ public boolean isKeyguardSecure() { try { - return mWM.isKeyguardSecure(); + return mWM.isKeyguardSecure(mContext.getUserId()); } catch (RemoteException ex) { return false; } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index db8c905eac34..41a992139111 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -781,6 +781,16 @@ public final class LoadedApk { isBundledApp = false; } + // Similar to vendor apks, we should add /product/lib for apks from product partition + // and not having /product/lib in the default search path + final boolean treatProductApkAsUnbundled = !defaultSearchPaths.contains("/product/lib"); + if (mApplicationInfo.getCodePath() != null + && mApplicationInfo.isProduct() && treatProductApkAsUnbundled + // TODO(b/128557860): Change target SDK version when version code R is available. + && getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) { + isBundledApp = false; + } + makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths); String libraryPermittedPath = mDataDir; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 23f64b86aade..523b2005fb72 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1569,12 +1569,12 @@ public class Notification implements Parcelable * Builder class for {@link Action} objects. */ public static final class Builder { - private final Icon mIcon; - private final CharSequence mTitle; - private final PendingIntent mIntent; + @Nullable private final Icon mIcon; + @Nullable private final CharSequence mTitle; + @Nullable private final PendingIntent mIntent; private boolean mAllowGeneratedReplies = true; - private final Bundle mExtras; - private ArrayList<RemoteInput> mRemoteInputs; + @NonNull private final Bundle mExtras; + @Nullable private ArrayList<RemoteInput> mRemoteInputs; private @SemanticAction int mSemanticAction; private boolean mIsContextual; @@ -1610,9 +1610,10 @@ public class Notification implements Parcelable action.getAllowGeneratedReplies(), action.getSemanticAction()); } - private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, - RemoteInput[] remoteInputs, boolean allowGeneratedReplies, - @SemanticAction int semanticAction) { + private Builder(@Nullable Icon icon, @Nullable CharSequence title, + @Nullable PendingIntent intent, @NonNull Bundle extras, + @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies, + @SemanticAction int semanticAction) { mIcon = icon; mTitle = title; mIntent = intent; @@ -1645,6 +1646,7 @@ public class Notification implements Parcelable * * <p>The returned Bundle is shared with this Builder. */ + @NonNull public Bundle getExtras() { return mExtras; } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 08e08806a310..4d280b76b3fa 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -101,11 +101,9 @@ import android.net.ConnectivityThread; import android.net.EthernetManager; import android.net.IConnectivityManager; import android.net.IEthernetManager; -import android.net.IIpMemoryStore; import android.net.IIpSecService; import android.net.INetworkPolicyManager; import android.net.ITestNetworkManager; -import android.net.IpMemoryStore; import android.net.IpSecManager; import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; @@ -340,17 +338,6 @@ final class SystemServiceRegistry { } }); - registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class, - new CachedServiceFetcher<IpMemoryStore>() { - @Override - public IpMemoryStore createService(final ContextImpl ctx) - throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow( - Context.IP_MEMORY_STORE_SERVICE); - IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b); - return new IpMemoryStore(ctx, service); - }}); - registerService(Context.IPSEC_SERVICE, IpSecManager.class, new CachedServiceFetcher<IpSecManager>() { @Override diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 9a4e2151dd3b..20e85e6793f1 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -112,6 +112,7 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -5171,7 +5172,8 @@ public class DevicePolicyManager { * </ul> * The call will fail if called with the package name of an unsupported VPN app. * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure - * of the VPN provider could break networking for all apps. + * of the VPN provider could break networking for all apps. This method clears any lockdown + * whitelist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}. * * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to * remove an existing always-on VPN configuration. @@ -5181,11 +5183,11 @@ public class DevicePolicyManager { * @throws NameNotFoundException if {@code vpnPackage} is not installed. * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being * set as always-on, or if always-on VPN is not available. - * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List) + * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) */ public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage, boolean lockdownEnabled) throws NameNotFoundException { - setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList()); + setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptySet()); } /** @@ -5195,6 +5197,11 @@ public class DevicePolicyManager { * System apps can always bypass VPN. * <p> Note that the system doesn't update the whitelist when packages are installed or * uninstalled, the admin app must call this method to keep the list up to date. + * <p> When {@code lockdownEnabled} is false {@code lockdownWhitelist} is ignored . When + * {@code lockdownEnabled} is {@code true} and {@code lockdownWhitelist} is {@code null} or + * empty, only system apps can bypass VPN. + * <p> Setting always-on VPN package to {@code null} or using + * {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} clears lockdown whitelist. * * @param vpnPackage package name for an installed VPN app on the device, or {@code null} * to remove an existing always-on VPN configuration @@ -5211,13 +5218,13 @@ public class DevicePolicyManager { * available. */ public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage, - boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) + boolean lockdownEnabled, @Nullable Set<String> lockdownWhitelist) throws NameNotFoundException { throwIfParentInstance("setAlwaysOnVpnPackage"); if (mService != null) { try { - mService.setAlwaysOnVpnPackage( - admin, vpnPackage, lockdownEnabled, lockdownWhitelist); + mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, + lockdownWhitelist == null ? null : new ArrayList<>(lockdownWhitelist)); } catch (ServiceSpecificException e) { switch (e.errorCode) { case ERROR_VPN_PACKAGE_NOT_FOUND: @@ -5255,7 +5262,7 @@ public class DevicePolicyManager { } /** - * Called by device or profile owner to query the list of packages that are allowed to access + * Called by device or profile owner to query the set of packages that are allowed to access * the network directly when always-on VPN is in lockdown mode but not connected. Returns * {@code null} when always-on VPN is not active or not in lockdown mode. * @@ -5263,13 +5270,15 @@ public class DevicePolicyManager { * * @throws SecurityException if {@code admin} is not a device or a profile owner. * - * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List) + * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) */ - public @Nullable List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) { + public @Nullable Set<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) { throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist"); if (mService != null) { try { - return mService.getAlwaysOnVpnLockdownWhitelist(admin); + final List<String> whitelist = + mService.getAlwaysOnVpnLockdownWhitelist(admin); + return whitelist == null ? null : new HashSet<>(whitelist); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -6339,7 +6348,6 @@ public class DevicePolicyManager { */ @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS, conditional = true) - @SystemApi public @Nullable ComponentName getProfileOwnerAsUser(@NonNull UserHandle user) { if (mService != null) { try { diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java index b6f37f6e30c5..298b0031d726 100644 --- a/core/java/android/app/prediction/AppPredictionContext.java +++ b/core/java/android/app/prediction/AppPredictionContext.java @@ -26,7 +26,8 @@ import android.os.Parcel; import android.os.Parcelable; /** - * TODO(b/111701043): Add java docs + * Class that provides contextual information about the environment in which the app prediction is + * used, such as package name, UI in which the app targets are shown, and number of targets. * * @hide */ @@ -57,20 +58,32 @@ public final class AppPredictionContext implements Parcelable { mExtras = parcel.readBundle(); } + /** + * Returns the UI surface of the prediction context. + */ @NonNull public String getUiSurface() { return mUiSurface; } + /** + * Returns the predicted target count + */ public @IntRange(from = 0) int getPredictedTargetCount() { return mPredictedTargetCount; } + /** + * Returns the package name of the prediction context. + */ @NonNull public String getPackageName() { return mPackageName; } + /** + * Returns the extras of the prediction context. + */ @Nullable public Bundle getExtras() { return mExtras; @@ -100,9 +113,6 @@ public final class AppPredictionContext implements Parcelable { dest.writeBundle(mExtras); } - /** - * @see Parcelable.Creator - */ public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionContext> CREATOR = new Parcelable.Creator<AppPredictionContext>() { public AppPredictionContext createFromParcel(Parcel parcel) { @@ -132,7 +142,7 @@ public final class AppPredictionContext implements Parcelable { private Bundle mExtras; /** - * TODO(b/123591863): Add java docs + * @param context The {@link Context} of the prediction client. * * @hide */ diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java index 45825cf93ae3..cb5b7e7763d9 100644 --- a/core/java/android/app/prediction/AppPredictionManager.java +++ b/core/java/android/app/prediction/AppPredictionManager.java @@ -23,7 +23,8 @@ import android.content.Context; import com.android.internal.util.Preconditions; /** - * TODO (b/111701043) : Add java doc + * Class that provides methods to create prediction clients. + * * @hide */ @SystemApi diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java index 1c5d8b49db2c..281a16f7715a 100644 --- a/core/java/android/app/prediction/AppPredictionSessionId.java +++ b/core/java/android/app/prediction/AppPredictionSessionId.java @@ -22,7 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; /** - * TODO (b/111701043) : Add java doc + * The id for an app prediction session. See {@link AppPredictor}. * * @hide */ @@ -33,6 +33,8 @@ public final class AppPredictionSessionId implements Parcelable { private final String mId; /** + * Creates a new id for a prediction session. + * * @hide */ public AppPredictionSessionId(@NonNull String id) { @@ -58,7 +60,6 @@ public final class AppPredictionSessionId implements Parcelable { @Override public int hashCode() { - // Ensure that the id has a consistent hash return mId.hashCode(); } @@ -72,9 +73,6 @@ public final class AppPredictionSessionId implements Parcelable { dest.writeString(mId); } - /** - * @see Parcelable.Creator - */ public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionSessionId> CREATOR = new Parcelable.Creator<AppPredictionSessionId>() { public AppPredictionSessionId createFromParcel(Parcel parcel) { diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java index 284327dac524..3e4e8dc2db72 100644 --- a/core/java/android/app/prediction/AppPredictor.java +++ b/core/java/android/app/prediction/AppPredictor.java @@ -39,7 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** - * TODO (b/111701043) : Add java doc + * Class that represents an App Prediction client. * * <p> * Usage: <pre> {@code @@ -49,14 +49,20 @@ import java.util.function.Consumer; * * void onCreate() { * mClient = new AppPredictor(...) + * mClient.registerPredictionUpdates(...) * } * * void onStart() { - * mClient.requestPredictionUpdate(); + * mClient.requestPredictionUpdate() + * } + * + * void onClick(...) { + * mClient.notifyAppTargetEvent(...) * } * * void onDestroy() { - * mClient.close(); + * mClient.unregisterPredictionUpdates() + * mClient.close() * } * * }</pre> @@ -83,7 +89,8 @@ public final class AppPredictor { * The caller should call {@link AppPredictor#destroy()} to dispose the client once it * no longer used. * - * @param predictionContext The prediction context + * @param context The {@link Context} of the user of this {@link AppPredictor}. + * @param predictionContext The prediction context. */ AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) { IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE); @@ -102,6 +109,8 @@ public final class AppPredictor { /** * Notifies the prediction service of an app target event. + * + * @param event The {@link AppTargetEvent} that represents the app target event. */ public void notifyAppTargetEvent(@NonNull AppTargetEvent event) { if (mIsClosed.get()) { @@ -118,6 +127,9 @@ public final class AppPredictor { /** * Notifies the prediction service when the targets in a launch location are shown to the user. + * + * @param launchLocation The launch location where the targets are shown to the user. + * @param targetIds List of {@link AppTargetId}s that are shown to the user. */ public void notifyLocationShown(@NonNull String launchLocation, @NonNull List<AppTargetId> targetIds) { @@ -138,7 +150,10 @@ public final class AppPredictor { * Requests the prediction service provide continuous updates of App predictions via the * provided callback, until the given callback is unregistered. * - * @see Callback#onTargetsAvailable(List) + * @see Callback#onTargetsAvailable(List). + * + * @param callbackExecutor The callback executor to use when calling the callback. + * @param callback The Callback to be called when updates of App predictions are available. */ public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor, @NonNull AppPredictor.Callback callback) { @@ -164,6 +179,10 @@ public final class AppPredictor { /** * Requests the prediction service to stop providing continuous updates to the provided * callback until the callback is re-registered. + * + * @see {@link AppPredictor#registerPredictionUpdates(Executor, Callback)}. + * + * @param callback The callback to be unregistered. */ public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) { if (mIsClosed.get()) { @@ -187,7 +206,7 @@ public final class AppPredictor { * Requests the prediction service to dispatch a new set of App predictions via the provided * callback. * - * @see Callback#onTargetsAvailable(List) + * @see Callback#onTargetsAvailable(List). */ public void requestPredictionUpdate() { if (mIsClosed.get()) { @@ -205,6 +224,10 @@ public final class AppPredictor { /** * Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the * ranker is not available. + * + * @param targets List of app targets to be sorted. + * @param callbackExecutor The callback executor to use when calling the callback. + * @param callback The callback to return the sorted list of app targets. */ @Nullable public void sortTargets(@NonNull List<AppTarget> targets, @@ -255,7 +278,7 @@ public final class AppPredictor { } /** - * TODO(b/123591863): Add java docs + * Returns the id of this prediction session. * * @hide */ @@ -271,7 +294,7 @@ public final class AppPredictor { /** * Called when a new set of predicted app targets are available. - * @param targets Sorted list of predicted targets + * @param targets Sorted list of predicted targets. */ void onTargetsAvailable(@NonNull List<AppTarget> targets); } diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java index 6f09d344c13f..bb1b96ce5f00 100644 --- a/core/java/android/app/prediction/AppTarget.java +++ b/core/java/android/app/prediction/AppTarget.java @@ -29,6 +29,7 @@ import com.android.internal.util.Preconditions; /** * A representation of a launchable target. + * * @hide */ @SystemApi @@ -45,7 +46,12 @@ public final class AppTarget implements Parcelable { private int mRank; /** - * TODO(b/123591863): Add java docs + * Creates an instance of AppTarget that represent a launchable component. + * + * @param id A unique id for this launchable target. + * @param packageName Package name of the target. + * @param className Class name of the target. + * @param user The UserHandle of the user which this target belongs to. * * @hide */ @@ -62,7 +68,11 @@ public final class AppTarget implements Parcelable { } /** - * TODO(b/123591863): Add java docs + * Creates an instance of AppTarget that represent a launchable shortcut. + * + * @param id A unique id for this launchable target. + * @param shortcutInfo The {@link ShortcutInfo} that is represented with this target. + * @param className Class name fo the target. * * @hide */ @@ -186,9 +196,6 @@ public final class AppTarget implements Parcelable { dest.writeInt(mRank); } - /** - * @see Parcelable.Creator - */ public static final @android.annotation.NonNull Parcelable.Creator<AppTarget> CREATOR = new Parcelable.Creator<AppTarget>() { public AppTarget createFromParcel(Parcel parcel) { diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java index f6964f3f4236..54b95639f68f 100644 --- a/core/java/android/app/prediction/AppTargetEvent.java +++ b/core/java/android/app/prediction/AppTargetEvent.java @@ -28,6 +28,7 @@ import java.lang.annotation.RetentionPolicy; /** * A representation of an app target event. + * * @hide */ @SystemApi @@ -118,9 +119,6 @@ public final class AppTargetEvent implements Parcelable { dest.writeInt(mAction); } - /** - * @see Creator - */ public static final @android.annotation.NonNull Creator<AppTargetEvent> CREATOR = new Creator<AppTargetEvent>() { public AppTargetEvent createFromParcel(Parcel parcel) { @@ -134,6 +132,7 @@ public final class AppTargetEvent implements Parcelable { /** * A builder for app target events. + * * @hide */ @SystemApi @@ -143,6 +142,10 @@ public final class AppTargetEvent implements Parcelable { private String mLocation; private @ActionType int mAction; + /** + * @param target The app target that is associated with this event. + * @param actionType The event type, which is one of the values in {@link ActionType}. + */ public Builder(@Nullable AppTarget target, @ActionType int actionType) { mTarget = target; mAction = actionType; diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java index aa2ec1fc3a62..3603f5f3ab10 100644 --- a/core/java/android/app/prediction/AppTargetId.java +++ b/core/java/android/app/prediction/AppTargetId.java @@ -22,7 +22,8 @@ import android.os.Parcel; import android.os.Parcelable; /** - * The id for a prediction target. + * The id for a prediction target. See {@link AppTarget}. + * * @hide */ @SystemApi @@ -33,7 +34,7 @@ public final class AppTargetId implements Parcelable { private final String mId; /** - * TODO(b/123591863): Add java docs + * Creates a new id for a prediction target. * * @hide */ @@ -49,6 +50,7 @@ public final class AppTargetId implements Parcelable { /** * Returns the id. + * * @hide */ @NonNull @@ -66,7 +68,6 @@ public final class AppTargetId implements Parcelable { @Override public int hashCode() { - // Ensure that the id has a consistent hash return mId.hashCode(); } @@ -80,9 +81,6 @@ public final class AppTargetId implements Parcelable { dest.writeString(mId); } - /** - * @see Creator - */ public static final @android.annotation.NonNull Creator<AppTargetId> CREATOR = new Creator<AppTargetId>() { public AppTargetId createFromParcel(Parcel parcel) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 49a29f0ac80d..fb933b1a7163 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3703,14 +3703,6 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a - * {@link android.net.IpMemoryStore} to store and read information about - * known networks. - * @hide - */ - public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore"; - - /** - * Use with {@link #getSystemService(String)} to retrieve a * {@link android.net.IpSecManager} for encrypting Sockets or Networks with * IPSec. * @@ -4016,6 +4008,16 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a + * {@link com.android.server.attention.AttentionManagerService} for attention services. + * + * @see #getSystemService(String) + * @see android.server.attention.AttentionManagerService + * @hide + */ + public static final String ATTENTION_SERVICE = "attention"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link android.view.inputmethod.InputMethodManager} for accessing input * methods. * diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index a2d3f6af2564..93a9daced987 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1997,7 +1997,8 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS"; /** - * Intent extra: ID of the shortcut used to send the share intent. + * Intent extra: ID of the shortcut used to send the share intent. Will be sent with + * {@link #ACTION_SEND}. * * @see ShortcutInfo#getId() * @@ -2437,7 +2438,7 @@ public class Intent implements Parcelable, Cloneable { * Broadcast Action: A rollback has been committed. * * <p class="note">This is a protected intent that can only be sent - * by the system. + * by the system. The receiver must hold MANAGE_ROLLBACK permission. * * @hide */ diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index 8e72fa5e1cfd..ceea0435a254 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -16,12 +16,14 @@ package android.content.om; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import java.util.List; @@ -96,6 +98,28 @@ public class OverlayManager { } /** + * Returns information about the overlay with the given package name for + * the specified user. + * + * @param packageName The name of the package. + * @param userHandle The user to get the OverlayInfos for. + * @return An OverlayInfo object; if no overlays exist with the + * requested package name, null is returned. + * + * @hide + */ + @SystemApi + @Nullable + public OverlayInfo getOverlayInfo(@NonNull final String packageName, + @NonNull final UserHandle userHandle) { + try { + return mService.getOverlayInfo(packageName, userHandle.myUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns information about all overlays for the given target package for * the specified user. The returned list is ordered according to the * overlay priority with the highest priority at the end of the list. diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 706cbbf560c5..068a93a253ff 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -671,6 +671,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE = 1 << 27; + /** + * Indicates whether this package is in fact a runtime resource overlay. + * + * @hide + */ + public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28; + + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -683,6 +691,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_HAS_DOMAIN_URLS, PRIVATE_FLAG_HIDDEN, PRIVATE_FLAG_INSTANT, + PRIVATE_FLAG_IS_RESOURCE_OVERLAY, PRIVATE_FLAG_ISOLATED_SPLIT_LOADING, PRIVATE_FLAG_OEM, PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, @@ -2023,6 +2032,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } /** + * Returns true if the package has declared in its manifest that it is a + * runtime resource overlay. + */ + public boolean isResourceOverlay() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY) != 0; + } + + /** * @hide */ @Override protected ApplicationInfo getApplicationInfo() { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index fd3529b05c35..464e866e0b31 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -742,7 +742,7 @@ interface IPackageManager { String getAppPredictionServicePackageName(); - String getContentCaptureServicePackageName(); + String getSystemCaptionsServicePackageName(); String getIncidentReportApproverPackageName(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 99324ba65f5c..2f99879d43a6 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2589,14 +2589,6 @@ public abstract class PackageManager { public static final String FEATURE_PC = "android.hardware.type.pc"; /** - * Feature for {@link #getSystemAvailableFeatures} and - * {@link #hasSystemFeature}: This is a foldable device. Properties such as - * the display size may change in response to being folded. - */ - @SdkConstant(SdkConstantType.FEATURE) - public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable"; - - /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: * The device supports printing. */ @@ -6863,9 +6855,9 @@ public abstract class PackageManager { * * @hide */ - public String getContentCaptureServicePackageName() { + public String getSystemCaptionsServicePackageName() { throw new UnsupportedOperationException( - "getContentCaptureServicePackageName not implemented in subclass"); + "getSystemCaptionsServicePackageName not implemented in subclass"); } /** diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 9d0ece0220b4..743a302cc543 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2108,6 +2108,9 @@ public class PackageParser { return null; } + pkg.applicationInfo.privateFlags |= + ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY; + XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_KEY_SETS)) { diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index 13c49a072277..3488cc30892c 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -307,9 +307,9 @@ public final class SharedLibraryInfo implements Parcelable { @Override public String toString() { - return "SharedLibraryInfo[name:" + mName + ", type:" + typeToString(mType) + return "SharedLibraryInfo{name:" + mName + ", type:" + typeToString(mType) + ", version:" + mVersion + (!getDependentPackages().isEmpty() - ? " has dependents" : ""); + ? " has dependents" : "") + "}"; } @Override diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 7b61807f9684..1f82fa6b57e3 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -1270,8 +1270,8 @@ public final class ShortcutInfo implements Parcelable { * system services even after it has been unpublished as a dynamic shortcut. */ @NonNull - public Builder setLongLived() { - mIsLongLived = true; + public Builder setLongLived(boolean londLived) { + mIsLongLived = londLived; return this; } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 67292426b248..6b8416d46601 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -191,9 +191,9 @@ public class Resources { /** * Return a global shared Resources object that provides access to only - * system resources (no application resources), and is not configured for - * the current screen (can not use dimension units, does not change based - * on orientation, etc). + * system resources (no application resources), is not configured for the + * current screen (can not use dimension units, does not change based on + * orientation, etc), and is not affected by Runtime Resource Overlay. */ public static Resources getSystem() { synchronized (sSync) { diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java index 9038b033c3c0..d54a6fe0a7b2 100644 --- a/core/java/android/content/rollback/RollbackManager.java +++ b/core/java/android/content/rollback/RollbackManager.java @@ -24,6 +24,7 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; import android.content.IntentSender; +import android.content.pm.PackageInstaller; import android.content.pm.ParceledListSlice; import android.content.pm.VersionedPackage; import android.os.RemoteException; @@ -48,6 +49,24 @@ public final class RollbackManager { private final String mCallerPackageName; private final IRollbackManager mBinder; + /** + * Lifetime duration of rollback packages in millis. A rollback will be available for + * at most that duration of time after a package is installed with + * {@link PackageInstaller.SessionParams#setEnableRollback()}. + * + * <p>If flag value is negative, the default value will be assigned. + * + * @see RollbackManager + * + * Flag type: {@code long} + * Namespace: NAMESPACE_ROLLBACK_BOOT + * + * @hide + */ + @TestApi + public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS = + "rollback_lifetime_in_millis"; + /** {@hide} */ public RollbackManager(Context context, IRollbackManager binder) { mCallerPackageName = context.getPackageName(); @@ -57,10 +76,12 @@ public final class RollbackManager { /** * Returns a list of all currently available rollbacks. * - * @throws SecurityException if the caller does not have the - * MANAGE_ROLLBACKS permission. + * @throws SecurityException if the caller does not have appropriate permissions. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) + @RequiresPermission(anyOf = { + android.Manifest.permission.MANAGE_ROLLBACKS, + android.Manifest.permission.TEST_MANAGE_ROLLBACKS + }) @NonNull public List<RollbackInfo> getAvailableRollbacks() { try { @@ -85,10 +106,12 @@ public final class RollbackManager { * rolled back from. * * @return the recently committed rollbacks - * @throws SecurityException if the caller does not have the - * MANAGE_ROLLBACKS permission. + * @throws SecurityException if the caller does not have appropriate permissions. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) + @RequiresPermission(anyOf = { + android.Manifest.permission.MANAGE_ROLLBACKS, + android.Manifest.permission.TEST_MANAGE_ROLLBACKS + }) public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() { try { return mBinder.getRecentlyExecutedRollbacks().getList(); @@ -171,10 +194,12 @@ public final class RollbackManager { * @param statusReceiver where to deliver the results. Intents sent to * this receiver contain {@link #EXTRA_STATUS} * and {@link #EXTRA_STATUS_MESSAGE}. - * @throws SecurityException if the caller does not have the - * MANAGE_ROLLBACKS permission. + * @throws SecurityException if the caller does not have appropriate permissions. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) + @RequiresPermission(anyOf = { + android.Manifest.permission.MANAGE_ROLLBACKS, + android.Manifest.permission.TEST_MANAGE_ROLLBACKS + }) public void commitRollback(int rollbackId, @NonNull List<VersionedPackage> causePackages, @NonNull IntentSender statusReceiver) { try { @@ -191,12 +216,11 @@ public final class RollbackManager { * across device reboot, by simulating what happens on reboot without * actually rebooting the device. * - * @throws SecurityException if the caller does not have the - * MANAGE_ROLLBACKS permission. + * @throws SecurityException if the caller does not have appropriate permissions. * * @hide */ - @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) + @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) @TestApi public void reloadPersistedData() { try { @@ -213,12 +237,11 @@ public final class RollbackManager { * recently committed rollbacks that contain the given package. * * @param packageName the name of the package to expire data for. - * @throws SecurityException if the caller does not have the - * MANAGE_ROLLBACKS permission. + * @throws SecurityException if the caller does not have appropriate permissions. * * @hide */ - @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) + @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) @TestApi public void expireRollbackForPackage(@NonNull String packageName) { try { diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java index d796003395f5..5e2875d02d90 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -176,6 +176,6 @@ public final class SQLiteGlobal { /** @hide */ public static boolean checkDbWipe() { - return true; + return false; } } diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java index 6ea35f01add0..bae0fd3ad3b9 100644 --- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java @@ -315,7 +315,7 @@ public interface BiometricFaceConstants { /** * The sensor is dirty. The user should be informed to clean the sensor. */ - public static final int SENSOR_DIRTY = 21; + public static final int FACE_ACQUIRED_SENSOR_DIRTY = 21; /** * Hardware vendors may extend this list if there are conditions that do not fall under one of diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java index 7fa1cfb7438e..21fcc63c76fb 100644 --- a/core/java/android/hardware/display/BrightnessChangeEvent.java +++ b/core/java/android/hardware/display/BrightnessChangeEvent.java @@ -80,15 +80,23 @@ public final class BrightnessChangeEvent implements Parcelable { * Histogram counting how many times a pixel of a given value was displayed onscreen for the * Value component of HSV if the device supports color sampling, if the device does not support * color sampling the value will be null. + * * The buckets of the histogram are evenly weighted, the number of buckets is device specific. - * For example if we had {10, 6, 4, 1} this means that 10 pixels were in the range - * [0x00,0x3f], 6 pixels were in the range [0x40,0x7f] etc. + * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed + * for 1 millisecond. + * For example if we had {100, 50, 30, 20}, value component was onscreen for 100 pixel + * milliseconds in range 0x00->0x3F, 30 pixel milliseconds in range 0x40->0x7F, etc. + * + * {@see #colorSampleDuration} */ @Nullable public final long[] colorValueBuckets; /** - * How many milliseconds of data are contained in the colorValueBuckets. + * How many milliseconds of data are contained in the colorValueBuckets, if the device does + * not support color sampling the value will be 0L. + * + * {@see #colorValueBuckets} */ public final long colorSampleDuration; @@ -283,7 +291,8 @@ public final class BrightnessChangeEvent implements Parcelable { return this; } - /** {@see BrightnessChangeEvent#valueBuckets} */ + /** {@see BrightnessChangeEvent#colorValueBuckets} + * {@see BrightnessChangeEvent#colorSampleDuration} */ public Builder setColorValues(@NonNull long[] colorValueBuckets, long colorSampleDuration) { Objects.requireNonNull(colorValueBuckets); mColorValueBuckets = colorValueBuckets; diff --git a/core/java/android/hardware/display/DisplayedContentSample.java b/core/java/android/hardware/display/DisplayedContentSample.java index 0610377c648a..4a429bb33fcb 100644 --- a/core/java/android/hardware/display/DisplayedContentSample.java +++ b/core/java/android/hardware/display/DisplayedContentSample.java @@ -30,12 +30,14 @@ public final class DisplayedContentSample { * Construct an object representing a color histogram of pixels that were displayed on screen. * * @param numFrames The number of frames represented by this sample. - * @param mSamplesComponent0 is a histogram counting how many times a pixel of a given value - * was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the histogram are evenly - * weighted, the number of buckets is device specific. - * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that 10 red pixels were - * displayed onscreen in range 0x00->0x3F, 6 red pixels were displayed onscreen in range - * 0x40->0x7F, etc. + * @param mSamplesComponent0 is a histogram counting how many times and for how long a pixel + * of a given value was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the + * histogram are evenly weighted, the number of buckets is device specific. + * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed + * onscreen for 1ms. + * eg, for RGBA_8888, if sampleComponent0 is {100, 50, 30, 20}, then red component was + * onscreen for 100 pixel milliseconds in range 0x00->0x3F, 30 pixel milliseconds in + * range 0x40->0x7F, etc. * @param mSamplesComponent1 is the same sample definition as sampleComponent0, but for the * second component of format. * @param mSamplesComponent2 is the same sample definition as sampleComponent0, but for the diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 139a5ee09dd8..3e8c334e8aa1 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -634,6 +634,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan return context.getString(R.string.face_acquired_obscured); case FACE_ACQUIRED_START: return null; + case FACE_ACQUIRED_SENSOR_DIRTY: + return context.getString(R.string.face_acquired_sensor_dirty); case FACE_ACQUIRED_VENDOR: { String[] msgArray = context.getResources().getStringArray( R.array.face_acquired_vendor); diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index f2087248205c..7873fc021b92 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -29,15 +29,33 @@ import android.os.RemoteException; * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity. */ public class CaptivePortal implements Parcelable { - /** @hide */ + /** + * Response code from the captive portal application, indicating that the portal was dismissed + * and the network should be re-validated. + * @see ICaptivePortal#appResponse(int) + * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) + * @hide + */ @SystemApi @TestApi public static final int APP_RETURN_DISMISSED = 0; - /** @hide */ + /** + * Response code from the captive portal application, indicating that the user did not login and + * does not want to use the captive portal network. + * @see ICaptivePortal#appResponse(int) + * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) + * @hide + */ @SystemApi @TestApi public static final int APP_RETURN_UNWANTED = 1; - /** @hide */ + /** + * Response code from the captive portal application, indicating that the user does not wish to + * login but wants to use the captive portal network as-is. + * @see ICaptivePortal#appResponse(int) + * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) + * @hide + */ @SystemApi @TestApi public static final int APP_RETURN_WANTED_AS_IS = 2; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index d08379fab047..e5802c23eb6f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2816,23 +2816,6 @@ public class ConnectivityManager { } /** - * @removed - * @deprecated This API would be removed when all of caller has been updated. - * */ - @Deprecated - public abstract static class TetheringEntitlementValueListener { - /** - * Called to notify entitlement result. - * - * @param resultCode a int value of entitlement result. It may be one of - * {@link #TETHER_ERROR_NO_ERROR}, - * {@link #TETHER_ERROR_PROVISION_FAILED}, or - * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}. - */ - public void onEntitlementResult(int resultCode) {} - } - - /** * Get the last value of the entitlement check on this downstream. If the cached value is * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the * cached value. Otherwise, a UI-based entitlement check would be performed. It is not @@ -2878,31 +2861,6 @@ public class ConnectivityManager { } /** - * @removed - * @deprecated This API would be removed when all of caller has been updated. - * */ - @Deprecated - public void getLatestTetheringEntitlementValue(int type, boolean showEntitlementUi, - @NonNull final TetheringEntitlementValueListener listener, @Nullable Handler handler) { - Preconditions.checkNotNull(listener, "TetheringEntitlementValueListener cannot be null."); - ResultReceiver wrappedListener = new ResultReceiver(handler) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - listener.onEntitlementResult(resultCode); - } - }; - - try { - String pkgName = mContext.getOpPackageName(); - Log.i(TAG, "getLatestTetheringEntitlementValue:" + pkgName); - mService.getLatestTetheringEntitlementResult(type, wrappedListener, - showEntitlementUi, pkgName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Report network connectivity status. This is currently used only * to alter status bar UI. * <p>This method requires the caller to hold the permission diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java index 0ac02b1b7b37..83e57e0a047b 100644 --- a/core/java/android/net/DnsPacket.java +++ b/core/java/android/net/DnsPacket.java @@ -71,7 +71,7 @@ public abstract class DnsPacket { } /** - * It's used both for DNS questions and DNS resource records. + * Superclass for DNS questions and DNS resource records. * * DNS questions (No TTL/RDATA) * DNS resource records (With TTL/RDATA) @@ -96,12 +96,13 @@ public abstract class DnsPacket { /** * Create a new DnsRecord from a positioned ByteBuffer. * - * @param ByteBuffer input of record, must be in network byte order - * (which is the default). * Reads the passed ByteBuffer from its current position and decodes a DNS record. * When this constructor returns, the reading position of the ByteBuffer has been * advanced to the end of the DNS header record. * This is meant to chain with other methods reading a DNS response in sequence. + * + * @param ByteBuffer input of record, must be in network byte order + * (which is the default). */ DnsRecord(int recordType, @NonNull ByteBuffer buf) throws BufferUnderflowException, ParseException { @@ -205,16 +206,6 @@ public abstract class DnsPacket { protected final DnsHeader mHeader; protected final List<DnsRecord>[] mRecords; - public static class ParseException extends Exception { - public ParseException(String msg) { - super(msg); - } - - public ParseException(String msg, Throwable cause) { - super(msg, cause); - } - } - protected DnsPacket(@NonNull byte[] data) throws ParseException { if (null == data) throw new ParseException("Parse header failed, null input data"); final ByteBuffer buffer; diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index d3bc3e66fbee..93b8cf801d45 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -22,11 +22,11 @@ import static android.net.NetworkUtils.resNetworkSend; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.Handler; -import android.os.MessageQueue; +import android.os.Looper; import android.system.ErrnoException; import android.util.Log; @@ -37,8 +37,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; - +import java.util.concurrent.Executor; /** * Dns resolver class for asynchronous dns querying @@ -81,66 +80,137 @@ public final class DnsResolver { public static final int FLAG_NO_CACHE_STORE = 1 << 1; public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2; - private static final int DNS_RAW_RESPONSE = 1; - private static final int NETID_UNSET = 0; private static final DnsResolver sInstance = new DnsResolver(); /** - * listener for receiving raw answers + * Get instance for DnsResolver + */ + public static @NonNull DnsResolver getInstance() { + return sInstance; + } + + private DnsResolver() {} + + /** + * Answer parser for parsing raw answers + * + * @param <T> The type of the parsed answer */ - public interface RawAnswerListener { + public interface AnswerParser<T> { /** - * {@code byte[]} is {@code null} if query timed out + * Creates a <T> answer by parsing the given raw answer. + * + * @param rawAnswer the raw answer to be parsed + * @return a parsed <T> answer + * @throws ParseException if parsing failed */ - void onAnswer(@Nullable byte[] answer); + @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException; } /** - * listener for receiving parsed answers + * Base class for answer callbacks + * + * @param <T> The type of the parsed answer */ - public interface InetAddressAnswerListener { + public abstract static class AnswerCallback<T> { + /** @hide */ + public final AnswerParser<T> parser; + + public AnswerCallback(@NonNull AnswerParser<T> parser) { + this.parser = parser; + }; + /** - * Will be called exactly once with all the answers to the query. - * size of addresses will be zero if no available answer could be parsed. + * Success response to + * {@link android.net.DnsResolver#query query()}. + * + * Invoked when the answer to a query was successfully parsed. + * + * @param answer parsed answer to the query. + * + * {@see android.net.DnsResolver#query query()} */ - void onAnswer(@NonNull List<InetAddress> addresses); + public abstract void onAnswer(@NonNull T answer); + + /** + * Error response to + * {@link android.net.DnsResolver#query query()}. + * + * Invoked when there is no valid answer to + * {@link android.net.DnsResolver#query query()} + * + * @param exception a {@link ParseException} object with additional + * detail regarding the failure + */ + public abstract void onParseException(@NonNull ParseException exception); + + /** + * Error response to + * {@link android.net.DnsResolver#query query()}. + * + * Invoked if an error happens when + * issuing the DNS query or receiving the result. + * {@link android.net.DnsResolver#query query()} + * + * @param exception an {@link ErrnoException} object with additional detail + * regarding the failure + */ + public abstract void onQueryException(@NonNull ErrnoException exception); } /** - * Get instance for DnsResolver + * Callback for receiving raw answers */ - public static DnsResolver getInstance() { - return sInstance; + public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> { + public RawAnswerCallback() { + super(rawAnswer -> rawAnswer); + } } - private DnsResolver() {} + /** + * Callback for receiving parsed {@link InetAddress} answers + * + * Note that if the answer does not contain any IP addresses, + * onAnswer will be called with an empty list. + */ + public abstract static class InetAddressAnswerCallback + extends AnswerCallback<List<InetAddress>> { + public InetAddressAnswerCallback() { + super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses()); + } + } /** - * Pass in a blob and corresponding setting, - * get a blob back asynchronously with the entire raw answer. + * Send a raw DNS query. + * The answer will be provided asynchronously through the provided {@link AnswerCallback}. * * @param network {@link Network} specifying which network for querying. * {@code null} for query on default network. * @param query blob message * @param flags flags as a combination of the FLAGS_* constants - * @param handler {@link Handler} to specify the thread - * upon which the {@link RawAnswerListener} will be invoked. - * @param listener a {@link RawAnswerListener} which will be called to notify the caller + * @param executor The {@link Executor} that the callback should be executed on. + * @param callback an {@link AnswerCallback} which will be called to notify the caller * of the result of dns query. */ - public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, - @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException { - final FileDescriptor queryfd = resNetworkSend((network != null + public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) { + final FileDescriptor queryfd; + try { + queryfd = resNetworkSend((network != null ? network.netId : NETID_UNSET), query, query.length, flags); - registerFDListener(handler.getLooper().getQueue(), queryfd, - answerbuf -> listener.onAnswer(answerbuf)); + } catch (ErrnoException e) { + callback.onQueryException(e); + return; + } + + registerFDListener(executor, queryfd, callback); } /** - * Pass in a domain name and corresponding setting, - * get a blob back asynchronously with the entire raw answer. + * Send a DNS query with the specified name, class and query type. + * The answer will be provided asynchronously through the provided {@link AnswerCallback}. * * @param network {@link Network} specifying which network for querying. * {@code null} for query on default network. @@ -148,74 +218,53 @@ public final class DnsResolver { * @param nsClass dns class as one of the CLASS_* constants * @param nsType dns resource record (RR) type as one of the TYPE_* constants * @param flags flags as a combination of the FLAGS_* constants - * @param handler {@link Handler} to specify the thread - * upon which the {@link RawAnswerListener} will be invoked. - * @param listener a {@link RawAnswerListener} which will be called to notify the caller + * @param executor The {@link Executor} that the callback should be executed on. + * @param callback an {@link AnswerCallback} which will be called to notify the caller * of the result of dns query. */ - public void query(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass, - @QueryType int nsType, @QueryFlag int flags, - @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException { - final FileDescriptor queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); - registerFDListener(handler.getLooper().getQueue(), queryfd, - answerbuf -> listener.onAnswer(answerbuf)); - } - - /** - * Pass in a domain name and corresponding setting, - * get back a set of InetAddresses asynchronously. - * - * @param network {@link Network} specifying which network for querying. - * {@code null} for query on default network. - * @param domain domain name for querying - * @param flags flags as a combination of the FLAGS_* constants - * @param handler {@link Handler} to specify the thread - * upon which the {@link InetAddressAnswerListener} will be invoked. - * @param listener an {@link InetAddressAnswerListener} which will be called to - * notify the caller of the result of dns query. - * - */ - public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags, - @NonNull Handler handler, @NonNull InetAddressAnswerListener listener) - throws ErrnoException { - final FileDescriptor v4fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags); - final FileDescriptor v6fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags); - - final InetAddressAnswerAccumulator accmulator = - new InetAddressAnswerAccumulator(2, listener); - final Consumer<byte[]> consumer = answerbuf -> - accmulator.accumulate(parseAnswers(answerbuf)); - - registerFDListener(handler.getLooper().getQueue(), v4fd, consumer); - registerFDListener(handler.getLooper().getQueue(), v6fd, consumer); + public <T> void query(@Nullable Network network, @NonNull String domain, + @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) { + final FileDescriptor queryfd; + try { + queryfd = resNetworkQuery((network != null + ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); + } catch (ErrnoException e) { + callback.onQueryException(e); + return; + } + registerFDListener(executor, queryfd, callback); } - private void registerFDListener(@NonNull MessageQueue queue, - @NonNull FileDescriptor queryfd, @NonNull Consumer<byte[]> answerConsumer) { - queue.addOnFileDescriptorEventListener( + private <T> void registerFDListener(@NonNull Executor executor, + @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) { + Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener( queryfd, FD_EVENTS, (fd, events) -> { - byte[] answerbuf = null; - try { - // TODO: Implement result function in Java side instead of using JNI - // Because JNI method close fd prior than unregistering fd on - // event listener. - answerbuf = resNetworkResult(fd); - } catch (ErrnoException e) { - Log.e(TAG, "resNetworkResult:" + e.toString()); - } - answerConsumer.accept(answerbuf); + executor.execute(() -> { + byte[] answerbuf = null; + try { + answerbuf = resNetworkResult(fd); + } catch (ErrnoException e) { + Log.e(TAG, "resNetworkResult:" + e.toString()); + answerCallback.onQueryException(e); + return; + } + try { + answerCallback.onAnswer( + answerCallback.parser.parse(answerbuf)); + } catch (ParseException e) { + answerCallback.onParseException(e); + } + }); // Unregister this fd listener return 0; }); } - private class DnsAddressAnswer extends DnsPacket { + private static class DnsAddressAnswer extends DnsPacket { private static final String TAG = "DnsResolver.DnsAddressAnswer"; private static final boolean DBG = false; @@ -226,12 +275,6 @@ public final class DnsResolver { if ((mHeader.flags & (1 << 15)) == 0) { throw new ParseException("Not an answer packet"); } - if (mHeader.rcode != 0) { - throw new ParseException("Response error, rcode:" + mHeader.rcode); - } - if (mHeader.getRecordCount(ANSECTION) == 0) { - throw new ParseException("No available answer"); - } if (mHeader.getRecordCount(QDSECTION) == 0) { throw new ParseException("No question found"); } @@ -241,6 +284,8 @@ public final class DnsResolver { public @NonNull List<InetAddress> getAddresses() { final List<InetAddress> results = new ArrayList<InetAddress>(); + if (mHeader.getRecordCount(ANSECTION) == 0) return results; + for (final DnsRecord ansSec : mRecords[ANSECTION]) { // Only support A and AAAA, also ignore answers if query type != answer type. int nsType = ansSec.nsType; @@ -259,34 +304,4 @@ public final class DnsResolver { } } - private @Nullable List<InetAddress> parseAnswers(@Nullable byte[] data) { - try { - return (data == null) ? null : new DnsAddressAnswer(data).getAddresses(); - } catch (DnsPacket.ParseException e) { - Log.e(TAG, "Parse answer fail " + e.getMessage()); - return null; - } - } - - private class InetAddressAnswerAccumulator { - private final List<InetAddress> mAllAnswers; - private final InetAddressAnswerListener mAnswerListener; - private final int mTargetAnswerCount; - private int mReceivedAnswerCount = 0; - - InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerListener listener) { - mTargetAnswerCount = size; - mAllAnswers = new ArrayList<>(); - mAnswerListener = listener; - } - - public void accumulate(@Nullable List<InetAddress> answer) { - if (null != answer) { - mAllAnswers.addAll(answer); - } - if (++mReceivedAnswerCount == mTargetAnswerCount) { - mAnswerListener.onAnswer(mAllAnswers); - } - } - } } diff --git a/media/java/android/media/session/SessionLink.aidl b/core/java/android/net/IIpMemoryStoreCallbacks.aidl index c3be23e8f6b7..53108dbca097 100644 --- a/media/java/android/media/session/SessionLink.aidl +++ b/core/java/android/net/IIpMemoryStoreCallbacks.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2019 The Android Open Source Project + * 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. @@ -14,6 +14,11 @@ * limitations under the License. */ -package android.media.session; +package android.net; -parcelable SessionLink; +import android.net.IIpMemoryStore; + +/** {@hide} */ +oneway interface IIpMemoryStoreCallbacks { + void onIpMemoryStoreFetched(in IIpMemoryStore ipMemoryStore); +} diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl index edb9df61044f..3751c36d6ee9 100644 --- a/core/java/android/net/INetworkStackConnector.aidl +++ b/core/java/android/net/INetworkStackConnector.aidl @@ -15,6 +15,7 @@ */ package android.net; +import android.net.IIpMemoryStoreCallbacks; import android.net.INetworkMonitorCallbacks; import android.net.Network; import android.net.dhcp.DhcpServingParamsParcel; @@ -27,4 +28,5 @@ oneway interface INetworkStackConnector { in IDhcpServerCallbacks cb); void makeNetworkMonitor(in Network network, String name, in INetworkMonitorCallbacks cb); void makeIpClient(in String ifName, in IIpClientCallbacks callbacks); -}
\ No newline at end of file + void fetchIpMemoryStore(in IIpMemoryStoreCallbacks cb); +} diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java index c638491291c2..c97b37b55c78 100644 --- a/core/java/android/net/InterfaceConfiguration.java +++ b/core/java/android/net/InterfaceConfiguration.java @@ -19,11 +19,9 @@ package android.net; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.text.TextUtils; import com.google.android.collect.Sets; -import java.net.InetAddress; import java.util.HashSet; /** @@ -117,40 +115,6 @@ public class InterfaceConfiguration implements Parcelable { } /** - * Construct InterfaceConfiguration from InterfaceConfigurationParcel. - */ - public static InterfaceConfiguration fromParcel(InterfaceConfigurationParcel p) { - InterfaceConfiguration cfg = new InterfaceConfiguration(); - cfg.setHardwareAddress(p.hwAddr); - - final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr); - cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength)); - for (String flag : p.flags) { - cfg.setFlag(flag); - } - - return cfg; - } - - /** - * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname. - */ - public InterfaceConfigurationParcel toParcel(String iface) { - InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel(); - cfgParcel.ifName = iface; - if (!TextUtils.isEmpty(mHwAddr)) { - cfgParcel.hwAddr = mHwAddr; - } else { - cfgParcel.hwAddr = ""; - } - cfgParcel.ipv4Addr = mAddr.getAddress().getHostAddress(); - cfgParcel.prefixLength = mAddr.getPrefixLength(); - cfgParcel.flags = mFlags.toArray(EMPTY_STRING_ARRAY); - - return cfgParcel; - } - - /** * This function determines if the interface is up and has a valid IP * configuration (IP address has a non zero octet). * diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index d42fce3a4c83..ae421a4991a4 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -40,6 +40,7 @@ import android.os.Parcelable; import android.util.BackupUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.io.ByteArrayOutputStream; @@ -89,10 +90,22 @@ public class NetworkTemplate implements Parcelable { private static boolean sForceAllNetworkTypes = false; + /** + * Results in matching against all mobile network types. + * + * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}. + */ + @VisibleForTesting public static void forceAllNetworkTypes() { sForceAllNetworkTypes = true; } + /** Resets the affect of {@link #forceAllNetworkTypes}. */ + @VisibleForTesting + public static void resetForceAllNetworkTypes() { + sForceAllNetworkTypes = false; + } + /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java index 2380e863d043..9d4727a84bc0 100644 --- a/core/java/android/net/ParseException.java +++ b/core/java/android/net/ParseException.java @@ -16,15 +16,22 @@ package android.net; +import android.annotation.NonNull; + /** - * Thrown when parsing a URL fails. + * Thrown when parsing failed. */ // See non-public class {@link WebAddress}. public class ParseException extends RuntimeException { public String response; - ParseException(String response) { + public ParseException(@NonNull String response) { super(response); this.response = response; } + + public ParseException(@NonNull String response, @NonNull Throwable cause) { + super(response, cause); + this.response = response; + } } diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java index d4a4cf436787..e56f05995cdc 100644 --- a/core/java/android/net/UidRange.java +++ b/core/java/android/net/UidRange.java @@ -19,14 +19,17 @@ package android.net; import static android.os.UserHandle.PER_USER_RANGE; import android.os.Parcel; +import android.os.Parcelable; /** * An inclusive range of UIDs. * * @hide */ -public final class UidRange extends UidRangeParcel { - private UidRange() {} +public final class UidRange implements Parcelable { + public final int start; + public final int stop; + public UidRange(int startUid, int stopUid) { if (startUid < 0) throw new IllegalArgumentException("Invalid start UID."); if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID."); @@ -86,18 +89,28 @@ public final class UidRange extends UidRangeParcel { return start + "-" + stop; } - /** - * DO NOT override "writeToParcel" and "readFromParcel" in this class. - * The parceling code is autogenerated by the superclass. - */ + // Implement the Parcelable interface + // TODO: Consider making this class no longer parcelable, since all users are likely in the + // system server. + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(start); + dest.writeInt(stop); + } public static final @android.annotation.NonNull Creator<UidRange> CREATOR = new Creator<UidRange>() { @Override public UidRange createFromParcel(Parcel in) { - UidRange obj = new UidRange(); - obj.readFromParcel(in); - return obj; + int start = in.readInt(); + int stop = in.readInt(); + + return new UidRange(start, stop); } @Override public UidRange[] newArray(int size) { diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index 870d8b1b7c22..ea245a4879c3 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -27,6 +27,8 @@ import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; import android.app.Service; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.IPackageManager; @@ -48,6 +50,7 @@ import java.net.InetAddress; import java.net.Socket; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * VpnService is a base class for applications to extend and build their @@ -138,7 +141,7 @@ public class VpnService extends Service { * provides users with the ability to set it as always-on, so that VPN connection is * persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device * owner and profile owner apps through - * {@link android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage}. + * {@link DevicePolicyManager#setAlwaysOnVpnPackage}. * * <p>VPN apps not supporting this feature should opt out by adding this meta-data field to the * {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one @@ -370,7 +373,10 @@ public class VpnService extends Service { } /** - * Returns whether the service is running in always-on VPN mode. + * Returns whether the service is running in always-on VPN mode. In this mode the system ensures + * that the service is always running by restarting it when necessary, e.g. after reboot. + * + * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) */ public final boolean isAlwaysOn() { try { @@ -381,8 +387,11 @@ public class VpnService extends Service { } /** - * Returns whether the service is running in always-on VPN mode blocking connections without - * VPN. + * Returns whether the service is running in always-on VPN lockdown mode. In this mode the + * system ensures that the service is always running and that the apps aren't allowed to bypass + * the VPN. + * + * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) */ public final boolean isLockdownEnabled() { try { diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java index e09fa8fd9e77..d6023d701762 100644 --- a/core/java/android/net/apf/ApfCapabilities.java +++ b/core/java/android/net/apf/ApfCapabilities.java @@ -19,17 +19,20 @@ package android.net.apf; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; import com.android.internal.R; /** * APF program support capabilities. * + * This class is immutable. * @hide */ @SystemApi @TestApi -public class ApfCapabilities { +public final class ApfCapabilities implements Parcelable { /** * Version of APF instruction set supported for packet filtering. 0 indicates no support for * packet filtering using APF programs. @@ -53,6 +56,37 @@ public class ApfCapabilities { this.apfPacketFormat = apfPacketFormat; } + private ApfCapabilities(Parcel in) { + apfVersionSupported = in.readInt(); + maximumApfProgramSize = in.readInt(); + apfPacketFormat = in.readInt(); + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(apfVersionSupported); + dest.writeInt(maximumApfProgramSize); + dest.writeInt(apfPacketFormat); + } + + public static final Creator<ApfCapabilities> CREATOR = new Creator<ApfCapabilities>() { + @Override + public ApfCapabilities createFromParcel(Parcel in) { + return new ApfCapabilities(in); + } + + @Override + public ApfCapabilities[] newArray(int size) { + return new ApfCapabilities[size]; + } + }; + @Override public String toString() { return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(), diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java index 5827f9ec9343..6f8aece848f8 100644 --- a/core/java/android/net/util/SocketUtils.java +++ b/core/java/android/net/util/SocketUtils.java @@ -45,7 +45,7 @@ import java.net.SocketException; */ @SystemApi @TestApi -public class SocketUtils { +public final class SocketUtils { /** * Create a raw datagram socket that is bound to an interface. * @@ -63,6 +63,7 @@ public class SocketUtils { /** * Make a socket address to communicate with netlink. */ + @NonNull public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) { return new NetlinkSocketAddress(portId, groupsMask); } @@ -70,13 +71,15 @@ public class SocketUtils { /** * Make socket address that packet sockets can bind to. */ - public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) { - return new PacketSocketAddress(protocol, ifIndex); + @NonNull + public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) { + return new PacketSocketAddress((short) protocol, ifIndex); } /** * Make a socket address that packet socket can send packets to. */ + @NonNull public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) { return new PacketSocketAddress(ifIndex, hwAddr); } diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 6432c242bfd5..b82e517c08ae 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -935,12 +935,16 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null + * Returns the value associated with the given key, or {@code null} if + * no mapping of the desired type exists for the given key or a {@code null} * value is explicitly associated with the key. * - * @param key a String, or null - * @return a Parcelable value, or null + * <p><b>Note: </b> if the expected value is not a class provided by the Android platform, + * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first. + * Otherwise, this method might throw an exception or return {@code null}. + * + * @param key a String, or {@code null} + * @return a Parcelable value, or {@code null} */ @Nullable public <T extends Parcelable> T getParcelable(@Nullable String key) { @@ -958,12 +962,16 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Returns the value associated with the given key, or null if + * Returns the value associated with the given key, or {@code null} if * no mapping of the desired type exists for the given key or a null * value is explicitly associated with the key. * - * @param key a String, or null - * @return a Parcelable[] value, or null + * <p><b>Note: </b> if the expected value is not a class provided by the Android platform, + * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first. + * Otherwise, this method might throw an exception or return {@code null}. + * + * @param key a String, or {@code null} + * @return a Parcelable[] value, or {@code null} */ @Nullable public Parcelable[] getParcelableArray(@Nullable String key) { @@ -981,12 +989,16 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null + * Returns the value associated with the given key, or {@code null} if + * no mapping of the desired type exists for the given key or a {@code null} * value is explicitly associated with the key. * - * @param key a String, or null - * @return an ArrayList<T> value, or null + * <p><b>Note: </b> if the expected value is not a class provided by the Android platform, + * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first. + * Otherwise, this method might throw an exception or return {@code null}. + * + * @param key a String, or {@code null} + * @return an ArrayList<T> value, or {@code null} */ @Nullable public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) { diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 39e91383c6a4..707a404da4ed 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -82,12 +82,18 @@ public class GraphicsEnvironment { public void setup(Context context, Bundle coreSettings) { final PackageManager pm = context.getPackageManager(); final String packageName = context.getPackageName(); + Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers"); setupGpuLayers(context, coreSettings, pm, packageName); + Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); + Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle"); setupAngle(context, coreSettings, pm, packageName); + Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); + Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver"); if (!chooseDriver(context, coreSettings, pm, packageName)) { setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE, SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName); } + Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); } /** diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 790bb27562a7..9c9829fb08e2 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1470,6 +1470,24 @@ public class UserManager { } /** + * Check if a user is a restricted profile. Restricted profiles may have a reduced number of + * available apps, app restrictions, and account restrictions. + * + * @param user the user to check + * @return whether the user is a restricted profile. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + public boolean isRestrictedProfile(@NonNull UserHandle user) { + try { + return mService.getUserInfo(user.getIdentifier()).isRestricted(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Checks if specified user can have restricted profile. * @hide */ diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 6d32f8cbe9ca..7fc07b05771c 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -78,6 +78,15 @@ public final class DeviceConfig { "activity_manager_native_boot"; /** + * Namespace for all app compat related features. These features will be applied + * immediately upon change. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_APP_COMPAT = "app_compat"; + + /** * Namespace for AttentionManagerService related features. * * @hide @@ -163,6 +172,22 @@ public final class DeviceConfig { public static final String NAMESPACE_NETD_NATIVE = "netd_native"; /** + * Namespace for Rollback flags that are applied immediately. + * + * @hide + */ + @SystemApi @TestApi + public static final String NAMESPACE_ROLLBACK = "rollback"; + + /** + * Namespace for Rollback flags that are applied after a reboot. + * + * @hide + */ + @SystemApi @TestApi + public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; + + /** * Namespace for all runtime related features that don't require a reboot to become active. * There are no feature flags using NAMESPACE_RUNTIME. * @@ -191,6 +216,23 @@ public final class DeviceConfig { public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot"; /** + * Namespace for system scheduler related features. These features will be applied + * immediately upon change. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_SCHEDULER = "scheduler"; + + /** + * Namespace for storage-related features. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_STORAGE = "storage"; + + /** * Namespace for System UI related features. * * @hide @@ -260,86 +302,6 @@ public final class DeviceConfig { String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration"; } - /** - * Namespace for Rollback. - * - * @hide - */ - @SystemApi @TestApi - public interface Rollback { - - /** - * Namespace for flags that can be changed immediately after becoming available on device. - */ - String NAMESPACE = "rollback"; - - /** - * Namespace for flags that can be changed only after reboot. - */ - String BOOT_NAMESPACE = "rollback_boot"; - - /** - * Timeout duration in milliseconds for enabling package rollback. If we fail to enable - * rollback within that period, the install will proceed without rollback enabled. - * - * <p>If flag value is negative, the default value will be assigned. - * - * Flag type: {@code long} - * Namespace: Rollback.NAMESPACE - */ - String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout"; - - /** - * Lifetime duration of rollback packages in millis. A rollback will be available for - * at most that duration of time after a package is installed with - * {@link PackageInstaller.SessionParams#setEnableRollback()}. - * - * <p>If flag value is negative, the default value will be assigned. - * - * @see RollbackManager - * - * Flag type: {@code long} - * Namespace: Rollback.BOOT_NAMESPACE - */ - String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis"; - } - - /** - * Namespace for storage-related features. - * - * @hide - */ - @SystemApi - public interface Storage { - String NAMESPACE = "storage"; - - /** - * If {@code 1}, enables the isolated storage feature. If {@code -1}, - * disables the isolated storage feature. If {@code 0}, uses the default - * value from the build system. - */ - String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; - } - - /** - * Namespace for system scheduler related features. These features will be applied - * immediately upon change. - * - * @hide - */ - @SystemApi - public interface Scheduler { - String NAMESPACE = "scheduler"; - - /** - * Flag for enabling fast metrics collection in system scheduler. - * A flag value of '' or '0' means the fast metrics collection is not - * enabled. Otherwise fast metrics collection is enabled and flag value - * is the order id. - */ - String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection"; - } - private static final Object sLock = new Object(); @GuardedBy("sLock") private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners = diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java index e931826d2455..8f772d4ec780 100644 --- a/core/java/android/provider/FontsContract.java +++ b/core/java/android/provider/FontsContract.java @@ -34,7 +34,6 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.net.Uri; -import android.os.Build.VERSION_CODES; import android.os.CancellationSignal; import android.os.Handler; import android.os.HandlerThread; @@ -652,17 +651,12 @@ public class FontsContract { if (familyBuilder == null) { familyBuilder = new FontFamily.Builder(font); } else { - try { - familyBuilder.addFont(font); - } catch (IllegalArgumentException e) { - if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) { - // Surpress the IllegalArgumentException for keeping the backward - // compatibility. - continue; - } - throw e; - } + familyBuilder.addFont(font); } + } catch (IllegalArgumentException e) { + // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion + // thrown by native code and returns null. + return null; } catch (IOException e) { continue; } diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java index 1549c45478ed..d505f02468d0 100644 --- a/core/java/android/provider/SearchIndexablesProvider.java +++ b/core/java/android/provider/SearchIndexablesProvider.java @@ -25,6 +25,7 @@ import android.content.UriMatcher; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.net.Uri; +import android.util.Log; /** * Base class for a search indexable provider. Such provider offers data to be indexed either @@ -112,19 +113,26 @@ public abstract class SearchIndexablesProvider extends ContentProvider { @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - switch (mMatcher.match(uri)) { - case MATCH_RES_CODE: - return queryXmlResources(null); - case MATCH_RAW_CODE: - return queryRawData(null); - case MATCH_NON_INDEXABLE_KEYS_CODE: - return queryNonIndexableKeys(null); - case MATCH_SITE_MAP_PAIRS_CODE: - return querySiteMapPairs(); - case MATCH_SLICE_URI_PAIRS_CODE: - return querySliceUriPairs(); - default: - throw new UnsupportedOperationException("Unknown Uri " + uri); + try { + switch (mMatcher.match(uri)) { + case MATCH_RES_CODE: + return queryXmlResources(null); + case MATCH_RAW_CODE: + return queryRawData(null); + case MATCH_NON_INDEXABLE_KEYS_CODE: + return queryNonIndexableKeys(null); + case MATCH_SITE_MAP_PAIRS_CODE: + return querySiteMapPairs(); + case MATCH_SLICE_URI_PAIRS_CODE: + return querySliceUriPairs(); + default: + throw new UnsupportedOperationException("Unknown Uri " + uri); + } + } catch (UnsupportedOperationException e) { + throw e; + } catch (Exception e) { + Log.e(TAG, "Provider querying exception:", e); + return null; } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 313384d668ef..63235a1c17e7 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1696,6 +1696,19 @@ public final class Settings { public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE"; + /** + * Activity Action: Show screen that let user manage how Android handles URL resolution. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing + * + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS"; + // End of Intent actions for Settings /** @@ -5594,6 +5607,7 @@ public final class Settings { * * @hide */ + @SystemApi public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR; @@ -12585,8 +12599,9 @@ public final class Settings { /** * Battery level [1-100] at which low power mode automatically turns on. - * Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically - * turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to + * If 0, it will not automatically turn on. For Q and newer, it will only automatically + * turn on if the value is greater than 0 and the {@link #AUTOMATIC_POWER_SAVER_MODE} + * setting is also set to * {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}. * * @see #AUTOMATIC_POWER_SAVER_MODE diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index 19e216a72d07..96b861b46dd4 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -30,6 +30,7 @@ import android.graphics.Rect; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; +import android.os.ICancellationSignal; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; @@ -201,18 +202,26 @@ public abstract class AugmentedAutofillService extends Service { if (mAutofillProxies == null) { mAutofillProxies = new SparseArray<>(); } + + final ICancellationSignal transport = CancellationSignal.createTransport(); + final CancellationSignal cancellationSignal = CancellationSignal.fromTransport(transport); AutofillProxy proxy = mAutofillProxies.get(sessionId); if (proxy == null) { proxy = new AutofillProxy(sessionId, client, taskId, componentName, focusedId, - focusedValue, requestTime, callback); + focusedValue, requestTime, callback, cancellationSignal); mAutofillProxies.put(sessionId, proxy); } else { // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId); proxy.update(focusedId, focusedValue, callback); } - // TODO(b/123101711): set cancellation signal - final CancellationSignal cancellationSignal = null; + + try { + callback.onCancellable(transport); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + onFillRequest(new FillRequest(proxy), cancellationSignal, new FillController(proxy), new FillCallback(proxy)); } @@ -329,18 +338,21 @@ public abstract class AugmentedAutofillService extends Service { @GuardedBy("mLock") private FillWindow mFillWindow; + private CancellationSignal mCancellationSignal; + private AutofillProxy(int sessionId, @NonNull IBinder client, int taskId, @NonNull ComponentName componentName, @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue, long requestTime, - @NonNull IFillCallback callback) { + @NonNull IFillCallback callback, @NonNull CancellationSignal cancellationSignal) { mSessionId = sessionId; mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client); mCallback = callback; this.taskId = taskId; this.componentName = componentName; - this.mFocusedId = focusedId; - this.mFocusedValue = focusedValue; - this.mFirstRequestTime = requestTime; + mFocusedId = focusedId; + mFocusedValue = focusedValue; + mFirstRequestTime = requestTime; + mCancellationSignal = cancellationSignal; // TODO(b/123099468): linkToDeath } @@ -394,6 +406,12 @@ public abstract class AugmentedAutofillService extends Service { public void requestShowFillUi(int width, int height, Rect anchorBounds, IAutofillWindowPresenter presenter) throws RemoteException { + if (mCancellationSignal.isCanceled()) { + if (VERBOSE) { + Log.v(TAG, "requestShowFillUi() not showing because request is cancelled"); + } + return; + } mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds, presenter); } @@ -408,8 +426,13 @@ public abstract class AugmentedAutofillService extends Service { mFocusedId = focusedId; mFocusedValue = focusedValue; if (mCallback != null) { - // TODO(b/123101711): we need to check whether the previous request was - // completed or not, and if not, cancel it first. + try { + if (!mCallback.isCompleted()) { + mCallback.cancel(); + } + } catch (RemoteException e) { + Slog.e(TAG, "failed to check current pending request status", e); + } Slog.d(TAG, "mCallback is updated."); } mCallback = callback; diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl index 2b0726649759..88baa878f118 100644 --- a/core/java/android/service/autofill/augmented/IFillCallback.aidl +++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl @@ -24,7 +24,8 @@ import android.os.ICancellationSignal; * @hide */ interface IFillCallback { - // TODO(b/123101711): add cancellation (after we have CTS tests, so we can test it) -// void onCancellable(in ICancellationSignal cancellation); + void onCancellable(in ICancellationSignal cancellation); void onSuccess(); + boolean isCompleted(); + void cancel(); } diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java index 5407c1d9b832..fc781c2035f6 100644 --- a/core/java/android/service/contentcapture/ActivityEvent.java +++ b/core/java/android/service/contentcapture/ActivityEvent.java @@ -52,11 +52,17 @@ public final class ActivityEvent implements Parcelable { */ public static final int TYPE_ACTIVITY_STOPPED = Event.ACTIVITY_STOPPED; + /** + * The activity was destroyed. + */ + public static final int TYPE_ACTIVITY_DESTROYED = Event.ACTIVITY_DESTROYED; + /** @hide */ @IntDef(prefix = { "TYPE_" }, value = { TYPE_ACTIVITY_RESUMED, TYPE_ACTIVITY_PAUSED, - TYPE_ACTIVITY_STOPPED + TYPE_ACTIVITY_STOPPED, + TYPE_ACTIVITY_DESTROYED }) @Retention(RetentionPolicy.SOURCE) public @interface ActivityEventType{} @@ -81,7 +87,8 @@ public final class ActivityEvent implements Parcelable { /** * Gets the event type. * - * @return either {@link #TYPE_ACTIVITY_RESUMED} or {@value #TYPE_ACTIVITY_PAUSED}. + * @return either {@link #TYPE_ACTIVITY_RESUMED}, {@value #TYPE_ACTIVITY_PAUSED}, + * {@value #TYPE_ACTIVITY_STOPPED}, or {@value #TYPE_ACTIVITY_DESTROYED}. */ @ActivityEventType public int getEventType() { @@ -97,6 +104,8 @@ public final class ActivityEvent implements Parcelable { return "ACTIVITY_PAUSED"; case TYPE_ACTIVITY_STOPPED: return "ACTIVITY_STOPPED"; + case TYPE_ACTIVITY_DESTROYED: + return "ACTIVITY_DESTROYED"; default: return "UKNOWN_TYPE: " + type; } diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 6f4114d1d81a..df113979bacf 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -78,6 +78,21 @@ public abstract class ContentCaptureService extends Service { public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; + /** + * Name under which a ContentCaptureService component publishes information about itself. + * + * <p>This meta-data should reference an XML resource containing a + * <code><{@link + * android.R.styleable#ContentCaptureService content-capture-service}></code> tag. + * + * <p>This is a a sample XML file configuring a ContentCaptureService: + * <pre> <content-capture-service + * android:settingsActivity="foo.bar.SettingsActivity" + * . . . + * /></pre> + */ + public static final String SERVICE_META_DATA = "android.content_capture"; + private Handler mHandler; private IContentCaptureServiceCallback mCallback; diff --git a/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java new file mode 100644 index 000000000000..6ecd82f50fdb --- /dev/null +++ b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java @@ -0,0 +1,171 @@ +/* + * 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 android.service.contentcapture; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.RemoteException; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.PrintWriter; + +/** + * {@link ServiceInfo} and meta-data about an {@link ContentCaptureService}. + * + * @hide + */ +public final class ContentCaptureServiceInfo { + + private static final String TAG = ContentCaptureServiceInfo.class.getSimpleName(); + private static final String XML_TAG_SERVICE = "content-capture-service"; + + private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp, + @UserIdInt int userId) throws PackageManager.NameNotFoundException { + int flags = PackageManager.GET_META_DATA; + if (!isTemp) { + flags |= PackageManager.MATCH_SYSTEM_ONLY; + } + + ServiceInfo si = null; + try { + si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId); + } catch (RemoteException e) { + } + if (si == null) { + throw new NameNotFoundException("Could not get serviceInfo for " + + (isTemp ? " (temp)" : "(default system)") + + " " + comp.flattenToShortString()); + } + return si; + } + + @NonNull + private final ServiceInfo mServiceInfo; + + @Nullable + private final String mSettingsActivity; + + public ContentCaptureServiceInfo(@NonNull Context context, @NonNull ComponentName comp, + boolean isTemporaryService, @UserIdInt int userId) + throws PackageManager.NameNotFoundException { + this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId)); + } + + private ContentCaptureServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) { + // Check for permissions. + if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) { + Slog.w(TAG, "ContentCaptureService from '" + si.packageName + + "' does not require permission " + + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + throw new SecurityException("Service does not require permission " + + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + } + + mServiceInfo = si; + + // Get the metadata, if declared. + final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(), + ContentCaptureService.SERVICE_META_DATA); + if (parser == null) { + mSettingsActivity = null; + return; + } + + String settingsActivity = null; + + try { + final Resources resources = context.getPackageManager().getResourcesForApplication( + si.applicationInfo); + + int type = 0; + while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { + type = parser.next(); + } + + if (XML_TAG_SERVICE.equals(parser.getName())) { + final AttributeSet allAttributes = Xml.asAttributeSet(parser); + TypedArray afsAttributes = null; + try { + afsAttributes = resources.obtainAttributes(allAttributes, + com.android.internal.R.styleable.ContentCaptureService); + settingsActivity = afsAttributes.getString( + R.styleable.ContentCaptureService_settingsActivity); + } finally { + if (afsAttributes != null) { + afsAttributes.recycle(); + } + } + } else { + Log.e(TAG, "Meta-data does not start with content-capture-service tag"); + } + } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { + Log.e(TAG, "Error parsing auto fill service meta-data", e); + } + + mSettingsActivity = settingsActivity; + } + + public ServiceInfo getServiceInfo() { + return mServiceInfo; + } + + @Nullable + public String getSettingsActivity() { + return mSettingsActivity; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(getClass().getSimpleName()); + builder.append("[").append(mServiceInfo); + builder.append(", settings:").append(mSettingsActivity); + return builder.toString(); + } + + /** + * Dumps it! + */ + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); + pw.print("Component: "); + pw.println(getServiceInfo().getComponentName()); + pw.print(prefix); + pw.print("Settings: "); + pw.println(mSettingsActivity); + } +} diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index cc74e1a329ed..8512a0bd8088 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -292,9 +292,9 @@ public class StatusBarNotification implements Parcelable { return uid; } - /** The package that posted the notification. - *<p> - * Might be different from {@link #getPackageName()} if the app owning the notification has + /** + * The package that posted the notification. + * <p> Might be different from {@link #getPackageName()} if the app owning the notification has * a {@link NotificationManager#setNotificationDelegate(String) notification delegate}. */ public @NonNull String getOpPkg() { diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 83f14d153bde..100774c896ca 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -536,7 +536,7 @@ public class TextToSpeech { * or playing back a file. The value should be one of the STREAM_ constants * defined in {@link AudioManager}. * - * @see TextToSpeech#speak(String, int, HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#playEarcon(String, int, HashMap) */ public static final String KEY_PARAM_STREAM = "streamType"; @@ -546,7 +546,7 @@ public class TextToSpeech { * speaking text or playing back a file. The value should be set * using {@link TextToSpeech#setAudioAttributes(AudioAttributes)}. * - * @see TextToSpeech#speak(String, int, HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#playEarcon(String, int, HashMap) * @hide */ @@ -557,7 +557,7 @@ public class TextToSpeech { * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been * spoken, a file has been played back or a silence duration has elapsed. * - * @see TextToSpeech#speak(String, int, HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#playEarcon(String, int, HashMap) * @see TextToSpeech#synthesizeToFile(String, HashMap, String) */ @@ -568,7 +568,7 @@ public class TextToSpeech { * volume used when speaking text. Volume is specified as a float ranging from 0 to 1 * where 0 is silence, and 1 is the maximum volume (the default behavior). * - * @see TextToSpeech#speak(String, int, HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#playEarcon(String, int, HashMap) */ public static final String KEY_PARAM_VOLUME = "volume"; @@ -578,7 +578,7 @@ public class TextToSpeech { * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan, * 0 to center (the default behavior), and +1 to hard-right. * - * @see TextToSpeech#speak(String, int, HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#playEarcon(String, int, HashMap) */ public static final String KEY_PARAM_PAN = "pan"; @@ -589,7 +589,7 @@ public class TextToSpeech { * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must * use network based synthesis. * - * @see TextToSpeech#speak(String, int, java.util.HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String) * @see TextToSpeech#getFeatures(java.util.Locale) * @@ -607,7 +607,7 @@ public class TextToSpeech { * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize * text on-device (without making network requests). * - * @see TextToSpeech#speak(String, int, java.util.HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String) * @see TextToSpeech#getFeatures(java.util.Locale) @@ -625,7 +625,7 @@ public class TextToSpeech { * output. It can be used to associate one of the {@link android.media.audiofx.AudioEffect} * objects with the synthesis (or earcon) output. * - * @see TextToSpeech#speak(String, int, HashMap) + * @see TextToSpeech#speak(CharSequence, int, Bundle, String) * @see TextToSpeech#playEarcon(String, int, HashMap) */ public static final String KEY_PARAM_SESSION_ID = "sessionId"; @@ -881,7 +881,7 @@ public class TextToSpeech { /** * Adds a mapping between a string of text and a sound resource in a * package. After a call to this method, subsequent calls to - * {@link #speak(String, int, HashMap)} will play the specified sound resource + * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource * if it is available, or synthesize the text it is missing. * * @param text @@ -915,7 +915,7 @@ public class TextToSpeech { /** * Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text * and a sound resource in a package. After a call to this method, subsequent calls to - * {@link #speak(String, int, HashMap)} will play the specified sound resource + * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource * if it is available, or synthesize the text it is missing. * * @param text @@ -947,11 +947,10 @@ public class TextToSpeech { } /** - * Adds a mapping between a string of text and a sound file. Using this, it - * is possible to add custom pronounciations for a string of text. - * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)} - * will play the specified sound resource if it is available, or synthesize the text it is - * missing. + * Adds a mapping between a string of text and a sound file. Using this, it is possible to + * add custom pronounciations for a string of text. After a call to this method, subsequent + * calls to {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound + * resource if it is available, or synthesize the text it is missing. * * @param text * The string of text. Example: <code>"south_south_east"</code> @@ -970,8 +969,8 @@ public class TextToSpeech { /** * Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file. - * Using this, it is possible to add custom pronounciations for a string of text. - * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)} + * Using this, it is possible to add custom pronounciations for a string of text. After a call + * to this method, subsequent calls to {@link #speak(CharSequence, int, Bundle, String)} * will play the specified sound resource if it is available, or synthesize the text it is * missing. * diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java index e43fd8303515..7cb91477738e 100644 --- a/core/java/android/text/style/LineBackgroundSpan.java +++ b/core/java/android/text/style/LineBackgroundSpan.java @@ -53,6 +53,15 @@ public interface LineBackgroundSpan extends ParagraphStyle /** * Default implementation of the {@link LineBackgroundSpan}, which changes the background * color of the lines to which the span is attached. + * <p> + * For example, an <code>LineBackgroundSpan</code> can be used like this: + * <pre> + * String text = "This is a multiline text. LineBackgroundSpan is applied here. This is a multiline text."; + * SpannableString string = new SpannableString(text); + * string.setSpan(new LineBackgroundSpan.Standard(Color.YELLOW), 26, 61, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + * </pre> + * <img src="{@docRoot}reference/android/images/text/style/linebackgroundspan.png" /> + * <figcaption>Text with <code>LineBackgroundSpan</code></figcaption> */ class Standard implements LineBackgroundSpan, ParcelableSpan { diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java index 7fb0f950f583..610cf2c7c784 100644 --- a/core/java/android/text/style/LineHeightSpan.java +++ b/core/java/android/text/style/LineHeightSpan.java @@ -70,7 +70,15 @@ public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan { * Default implementation of the {@link LineHeightSpan}, which changes the line height of the * attached paragraph. * <p> - * LineHeightSpan will change the line height of the entire paragraph, even though it + * For example, a paragraph with its line height equal to 100px can be set like this: + * <pre> + * SpannableString string = new SpannableString("This is a multiline paragraph. This is a multiline paragraph."); + * string.setSpan(new LineHeightSpan.Standard(100), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + * </pre> + * <img src="{@docRoot}reference/android/images/text/style/lineheightspan.png" /> + * <figcaption>Text with line height set to 100 pixels.</figcaption> + * <p> + * Notice that LineHeightSpan will change the line height of the entire paragraph, even though it * covers only part of the paragraph. * </p> */ diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl new file mode 100644 index 000000000000..a032625547d2 --- /dev/null +++ b/core/java/android/view/ISystemGestureExclusionListener.aidl @@ -0,0 +1,34 @@ +/** + * 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 android.view; + +import android.graphics.Region; + +/** + * Listener for changes to the system gesture exclusion region + * + * {@hide} + */ +oneway interface ISystemGestureExclusionListener { + /** + * Called when the system gesture exclusion for the given display changed. + * @param displayId the display whose system gesture exclusion changed + * @param systemGestureExclusion a {@code Region} where the app would like priority over the + * system gestures, in display coordinates. + */ + void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion); +}
\ No newline at end of file diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index e32c4e136a6e..b91b93f7e09c 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -40,6 +40,7 @@ import android.view.IOnKeyguardExitResult; import android.view.IPinnedStackListener; import android.view.RemoteAnimationAdapter; import android.view.IRotationWatcher; +import android.view.ISystemGestureExclusionListener; import android.view.IWallpaperVisibilityListener; import android.view.IWindowSession; import android.view.IWindowSessionCallback; @@ -129,7 +130,7 @@ interface IWindowManager @UnsupportedAppUsage boolean isKeyguardLocked(); @UnsupportedAppUsage - boolean isKeyguardSecure(); + boolean isKeyguardSecure(int userId); void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message); // Requires INTERACT_ACROSS_USERS_FULL permission @@ -281,6 +282,18 @@ interface IWindowManager int displayId); /** + * Registers a system gesture exclusion listener for a given display. + */ + void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId); + + /** + * Unregisters a system gesture exclusion listener for a given display. + */ + void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId); + + /** * Used only for assist -- request a screenshot of the current application. */ boolean requestAssistScreenshot(IAssistDataReceiver receiver); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 1fcd4321cdde..87efb3fbf6c0 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -32,6 +32,8 @@ import android.view.InsetsState; import android.view.Surface; import android.view.SurfaceControl; +import java.util.List; + /** * System private per-application interface to the window manager. * @@ -265,4 +267,10 @@ interface IWindowSession { * that new state. */ void insetsModified(IWindow window, in InsetsState state); + + + /** + * Called when the system gesture exclusion has changed. + */ + void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects); } diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 2d7e17961279..6129b38104af 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -145,7 +145,14 @@ public class InsetsState implements Parcelable { // TODO: set system gesture insets based on actual system gesture area. typeInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets); - typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets); + typeInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] = + Insets.of(legacyContentInsets); + typeInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyContentInsets); + + typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyStableInsets); + typeMaxInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] = + Insets.of(legacyStableInsets); + typeMaxInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyStableInsets); } for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) { InsetsSource source = mSources.get(type); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 49eb78d63479..bf0f4e29a4f3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -130,8 +130,8 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.view.inspector.InspectableProperty; -import android.view.inspector.InspectableProperty.EnumMap; -import android.view.inspector.InspectableProperty.FlagMap; +import android.view.inspector.InspectableProperty.EnumEntry; +import android.view.inspector.InspectableProperty.FlagEntry; import android.widget.Checkable; import android.widget.FrameLayout; import android.widget.ScrollBarDrawable; @@ -6902,13 +6902,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return a bitmask representing the enabled scroll indicators */ @InspectableProperty(flagMapping = { - @FlagMap(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), - @FlagMap(target = SCROLL_INDICATOR_TOP, name = "top"), - @FlagMap(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), - @FlagMap(target = SCROLL_INDICATOR_LEFT, name = "left"), - @FlagMap(target = SCROLL_INDICATOR_RIGHT, name = "right"), - @FlagMap(target = SCROLL_INDICATOR_START, name = "start"), - @FlagMap(target = SCROLL_INDICATOR_END, name = "end") + @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), + @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), + @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), + @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), + @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), + @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), + @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") }) @ScrollIndicators public int getScrollIndicators() { @@ -9037,12 +9037,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, to = "noExcludeDescendants")}) @InspectableProperty(enumMapping = { - @EnumMap(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), - @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), - @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), - @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, + @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), + @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), + @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), + @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, name = "yesExcludeDescendants"), - @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, + @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, name = "noExcludeDescendants"), }) public @AutofillImportance int getImportantForAutofill() { @@ -9230,12 +9230,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, to = "noExcludeDescendants")}) @InspectableProperty(enumMapping = { - @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), - @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), - @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), - @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, + @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), + @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), + @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), + @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, name = "yesExcludeDescendants"), - @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, + @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, name = "noExcludeDescendants"), }) public @ContentCaptureImportance int getImportantForContentCapture() { @@ -10539,9 +10539,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Deprecated @DrawingCacheQuality @InspectableProperty(enumMapping = { - @EnumMap(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), - @EnumMap(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), - @EnumMap(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") + @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), + @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), + @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") }) public int getDrawingCacheQuality() { return mViewFlags & DRAWING_CACHE_QUALITY_MASK; @@ -11095,11 +11095,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p>Computes the coordinates of this view in its surface. The argument * must be an array of two integers. After the method returns, the array * contains the x and y location in that order.</p> - * @hide + * * @param location an array of two integers in which to hold the coordinates */ - @UnsupportedAppUsage - public void getLocationInSurface(@Size(2) int[] location) { + public void getLocationInSurface(@NonNull @Size(2) int[] location) { getLocationInWindow(location); if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; @@ -11281,9 +11280,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = GONE, to = "GONE") }) @InspectableProperty(enumMapping = { - @EnumMap(value = VISIBLE, name = "visible"), - @EnumMap(value = INVISIBLE, name = "invisible"), - @EnumMap(value = GONE, name = "gone") + @EnumEntry(value = VISIBLE, name = "visible"), + @EnumEntry(value = INVISIBLE, name = "invisible"), + @EnumEntry(value = GONE, name = "gone") }) @Visibility public int getVisibility() { @@ -11532,10 +11531,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") }) @InspectableProperty(hasAttributeId = false, enumMapping = { - @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"), - @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl"), - @EnumMap(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), - @EnumMap(value = LAYOUT_DIRECTION_LOCALE, name = "locale") + @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), + @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), + @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), + @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") }) @LayoutDir public int getRawLayoutDirection() { @@ -11591,8 +11590,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") }) @InspectableProperty(enumMapping = { - @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"), - @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl") + @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), + @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") }) @ResolvedLayoutDir public int getLayoutDirection() { @@ -12077,9 +12076,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") }, category = "focus") @InspectableProperty(enumMapping = { - @EnumMap(value = NOT_FOCUSABLE, name = "false"), - @EnumMap(value = FOCUSABLE, name = "true"), - @EnumMap(value = FOCUSABLE_AUTO, name = "auto") + @EnumEntry(value = NOT_FOCUSABLE, name = "false"), + @EnumEntry(value = FOCUSABLE, name = "true"), + @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") }) @Focusable public int getFocusable() { @@ -12962,10 +12961,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, to = "noHideDescendants") }) @InspectableProperty(enumMapping = { - @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), - @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), - @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), - @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, + @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), + @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), + @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), + @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, name = "noHideDescendants"), }) public int getImportantForAccessibility() { @@ -13021,9 +13020,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #setAccessibilityLiveRegion(int) */ @InspectableProperty(enumMapping = { - @EnumMap(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), - @EnumMap(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), - @EnumMap(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") + @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), + @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), + @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") }) public int getAccessibilityLiveRegion() { return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) @@ -18651,9 +18650,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ @InspectableProperty(name = "requiresFadingEdge", flagMapping = { - @FlagMap(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), - @FlagMap(target = FADING_EDGE_VERTICAL, name = "vertical"), - @FlagMap(target = FADING_EDGE_HORIZONTAL, name = "horizontal") + @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), + @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), + @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") }) public int getFadingEdge() { return mViewFlags & FADING_EDGE_MASK; @@ -18948,10 +18947,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") }) @InspectableProperty(name = "scrollbarStyle", enumMapping = { - @EnumMap(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), - @EnumMap(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), - @EnumMap(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), - @EnumMap(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") + @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), + @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), + @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), + @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") }) @ScrollBarStyle public int getScrollBarStyle() { @@ -20504,9 +20503,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #LAYER_TYPE_HARDWARE */ @InspectableProperty(enumMapping = { - @EnumMap(value = LAYER_TYPE_NONE, name = "none"), - @EnumMap(value = LAYER_TYPE_SOFTWARE, name = "software"), - @EnumMap(value = LAYER_TYPE_HARDWARE, name = "hardware") + @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), + @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), + @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") }) @LayerType public int getLayerType() { @@ -26187,9 +26186,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return This view's over-scroll mode. */ @InspectableProperty(enumMapping = { - @EnumMap(value = OVER_SCROLL_ALWAYS, name = "always"), - @EnumMap(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), - @EnumMap(value = OVER_SCROLL_NEVER, name = "never") + @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), + @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), + @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") }) public int getOverScrollMode() { return mOverScrollMode; @@ -26580,14 +26579,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") }) @InspectableProperty(hasAttributeId = false, enumMapping = { - @EnumMap(value = TEXT_DIRECTION_INHERIT, name = "inherit"), - @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"), - @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), - @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"), - @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"), - @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), - @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), - @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), + @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), + @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), + @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), + @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), + @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), + @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), + @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), + @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), }) @UnsupportedAppUsage public int getRawTextDirection() { @@ -26657,13 +26656,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") }) @InspectableProperty(hasAttributeId = false, enumMapping = { - @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"), - @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), - @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"), - @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"), - @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), - @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), - @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), + @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), + @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), + @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), + @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), + @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), + @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), + @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), }) public int getTextDirection() { return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; @@ -26837,13 +26836,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") }) @InspectableProperty(hasAttributeId = false, enumMapping = { - @EnumMap(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), - @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), - @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), - @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), - @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"), - @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), - @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") + @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), + @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), + @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), + @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), + @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), + @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), + @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") }) @TextAlignment @UnsupportedAppUsage @@ -26912,12 +26911,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") }) @InspectableProperty(enumMapping = { - @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), - @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), - @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), - @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"), - @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), - @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") + @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), + @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), + @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), + @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), + @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), + @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") }) @TextAlignment public int getTextAlignment() { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 4964ee1f0d28..a4d80dcfe7d2 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -61,7 +61,7 @@ import android.view.animation.LayoutAnimationController; import android.view.animation.Transformation; import android.view.autofill.Helper; import android.view.inspector.InspectableProperty; -import android.view.inspector.InspectableProperty.EnumMap; +import android.view.inspector.InspectableProperty.EnumEntry; import com.android.internal.R; @@ -778,9 +778,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS") }) @InspectableProperty(enumMapping = { - @EnumMap(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"), - @EnumMap(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"), - @EnumMap(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants") + @EnumEntry(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"), + @EnumEntry(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"), + @EnumEntry(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants") }) public int getDescendantFocusability() { return mGroupFlags & FLAG_MASK_FOCUSABILITY; @@ -6574,10 +6574,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL") }) @InspectableProperty(enumMapping = { - @EnumMap(value = PERSISTENT_NO_CACHE, name = "none"), - @EnumMap(value = PERSISTENT_ANIMATION_CACHE, name = "animation"), - @EnumMap(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"), - @EnumMap(value = PERSISTENT_ALL_CACHES, name = "all"), + @EnumEntry(value = PERSISTENT_NO_CACHE, name = "none"), + @EnumEntry(value = PERSISTENT_ANIMATION_CACHE, name = "animation"), + @EnumEntry(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"), + @EnumEntry(value = PERSISTENT_ALL_CACHES, name = "all"), }) public int getPersistentDrawingCache() { return mPersistentDrawingCache; @@ -6657,8 +6657,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @see #setLayoutMode(int) */ @InspectableProperty(enumMapping = { - @EnumMap(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"), - @EnumMap(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds") + @EnumEntry(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"), + @EnumEntry(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds") }) public int getLayoutMode() { if (mLayoutMode == LAYOUT_MODE_UNDEFINED) { @@ -7849,8 +7849,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT") }) @InspectableProperty(name = "layout_width", enumMapping = { - @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT), - @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT) + @EnumEntry(name = "match_parent", value = MATCH_PARENT), + @EnumEntry(name = "wrap_content", value = WRAP_CONTENT) }) public int width; @@ -7864,8 +7864,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT") }) @InspectableProperty(name = "layout_height", enumMapping = { - @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT), - @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT) + @EnumEntry(name = "match_parent", value = MATCH_PARENT), + @EnumEntry(name = "wrap_content", value = WRAP_CONTENT) }) public int height; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index a28d6622c40f..6d04cd3187ef 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3987,7 +3987,11 @@ public final class ViewRootImpl implements ViewParent, void systemGestureExclusionChanged() { final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects(); if (rectsForWindowManager != null) { - // TODO Send to WM + try { + mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } mAttachInfo.mTreeObserver .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager); } diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index f1a992cb45fa..aac0e34de0da 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -20,14 +20,18 @@ package android.view; import static android.view.WindowInsets.Type.FIRST; import static android.view.WindowInsets.Type.IME; import static android.view.WindowInsets.Type.LAST; +import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES; import static android.view.WindowInsets.Type.SIDE_BARS; import static android.view.WindowInsets.Type.SIZE; import static android.view.WindowInsets.Type.SYSTEM_GESTURES; +import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT; import static android.view.WindowInsets.Type.TOP_BAR; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.compatSystemInsets; import static android.view.WindowInsets.Type.indexOf; +import static android.view.WindowInsets.Type.mandatorySystemGestures; import static android.view.WindowInsets.Type.systemGestures; +import static android.view.WindowInsets.Type.tappableElement; import android.annotation.IntDef; import android.annotation.IntRange; @@ -223,6 +227,8 @@ public final class WindowInsets { assignCompatInsets(typeInsetMap, insets); // TODO: set system gesture insets based on actual system gesture area. typeInsetMap[indexOf(systemGestures())] = Insets.of(insets); + typeInsetMap[indexOf(mandatorySystemGestures())] = Insets.of(insets); + typeInsetMap[indexOf(tappableElement())] = Insets.of(insets); return typeInsetMap; } @@ -639,15 +645,22 @@ public final class WindowInsets { * priority and may consume some or all touch input, e.g. due to the a system bar * occupying it, or it being reserved for touch-only gestures. * + * <p>An app can declare priority over system gestures with + * {@link View#setSystemGestureExclusionRects} outside of the + * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}. + * * <p>Simple taps are guaranteed to reach the window even within the system gesture insets, - * as long as they are outside the {@link #getSystemWindowInsets() system window insets}. + * as long as they are outside the {@link #getTappableElementInsets() system window insets}. * * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned * even when the system gestures are inactive due to * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}. * - * <p>This inset does not affect the result of {@link #isConsumed()} and cannot be consumed. + * <p>This inset is consumed together with the {@link #getSystemWindowInsets() + * system window insets} by {@link #consumeSystemWindowInsets()}. + * + * @see #getMandatorySystemGestureInsets */ @NonNull public Insets getSystemGestureInsets() { @@ -655,6 +668,60 @@ public final class WindowInsets { } /** + * Returns the mandatory system gesture insets. + * + * <p>The mandatory system gesture insets represent the area of a window where mandatory system + * gestures have priority and may consume some or all touch input, e.g. due to the a system bar + * occupying it, or it being reserved for touch-only gestures. + * + * <p>In contrast to {@link #getSystemGestureInsets regular system gestures}, <b>mandatory</b> + * system gestures cannot be overriden by {@link View#setSystemGestureExclusionRects}. + * + * <p>Simple taps are guaranteed to reach the window even within the system gesture insets, + * as long as they are outside the {@link #getTappableElementInsets() system window insets}. + * + * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned + * even when the system gestures are inactive due to + * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or + * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}. + * + * <p>This inset is consumed together with the {@link #getSystemWindowInsets() + * system window insets} by {@link #consumeSystemWindowInsets()}. + * + * @see #getSystemGestureInsets + */ + @NonNull + public Insets getMandatorySystemGestureInsets() { + return getInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES); + } + + /** + * Returns the tappable element insets. + * + * <p>The tappable element insets represent how much tappable elements <b>must at least</b> be + * inset to remain both tappable and visually unobstructed by persistent system windows. + * + * <p>This may be smaller than {@link #getSystemWindowInsets()} if the system window is + * largely transparent and lets through simple taps (but not necessarily more complex gestures). + * + * <p>Note that generally, tappable elements <strong>should</strong> be aligned with the + * {@link #getSystemWindowInsets() system window insets} instead to avoid overlapping with the + * system bars. + * + * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned + * even when the area covered by the inset would be tappable due to + * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or + * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}. + * + * <p>This inset is consumed together with the {@link #getSystemWindowInsets() + * system window insets} by {@link #consumeSystemWindowInsets()}. + */ + @NonNull + public Insets getTappableElementInsets() { + return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT); + } + + /** * Returns a copy of this WindowInsets with the stable insets fully consumed. * * @return A modified copy of this WindowInsets @@ -895,6 +962,41 @@ public final class WindowInsets { } /** + * Sets mandatory system gesture insets in pixels. + * + * <p>The mandatory system gesture insets represent the area of a window where mandatory + * system gestures have priority and may consume some or all touch input, e.g. due to the a + * system bar occupying it, or it being reserved for touch-only gestures. + * + * <p>In contrast to {@link #setSystemGestureInsets regular system gestures}, + * <b>mandatory</b> system gestures cannot be overriden by + * {@link View#setSystemGestureExclusionRects}. + * + * @see #getMandatorySystemGestureInsets() + * @return itself + */ + @NonNull + public Builder setMandatorySystemGestureInsets(@NonNull Insets insets) { + WindowInsets.setInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES, insets); + return this; + } + + /** + * Sets tappable element insets in pixels. + * + * <p>The tappable element insets represent how much tappable elements <b>must at least</b> + * be inset to remain both tappable and visually unobstructed by persistent system windows. + * + * @see #getTappableElementInsets() + * @return itself + */ + @NonNull + public Builder setTappableElementInsets(@NonNull Insets insets) { + WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets); + return this; + } + + /** * Sets the insets of a specific window type in pixels. * * <p>The insets represents the area of a a window that is partially or fully obscured by @@ -1041,16 +1143,18 @@ public final class WindowInsets { */ public static final class Type { - static final int FIRST = 0x1; + static final int FIRST = 1 << 0; static final int TOP_BAR = FIRST; - static final int IME = 0x2; - static final int SIDE_BARS = 0x4; + static final int IME = 1 << 1; + static final int SIDE_BARS = 1 << 2; - static final int SYSTEM_GESTURES = 0x8; + static final int SYSTEM_GESTURES = 1 << 3; + static final int MANDATORY_SYSTEM_GESTURES = 1 << 4; + static final int TAPPABLE_ELEMENT = 1 << 5; - static final int LAST = 0x10; - static final int SIZE = 5; + static final int LAST = 1 << 6; + static final int SIZE = 7; static final int WINDOW_DECOR = LAST; static int indexOf(@InsetType int type) { @@ -1063,8 +1167,12 @@ public final class WindowInsets { return 2; case SYSTEM_GESTURES: return 3; - case WINDOW_DECOR: + case MANDATORY_SYSTEM_GESTURES: return 4; + case TAPPABLE_ELEMENT: + return 5; + case WINDOW_DECOR: + return 6; default: throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST," + " type=" + type); @@ -1076,7 +1184,8 @@ public final class WindowInsets { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES }) + @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES, + MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT}) public @interface InsetType { } @@ -1131,6 +1240,20 @@ public final class WindowInsets { } /** + * @see #getMandatorySystemGestureInsets + */ + public static @InsetType int mandatorySystemGestures() { + return MANDATORY_SYSTEM_GESTURES; + } + + /** + * @see #getTappableElementInsets + */ + public static @InsetType int tappableElement() { + return TAPPABLE_ELEMENT; + } + + /** * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but * not {@link #ime()}. */ diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 604cce52d5bd..8f1896d76b9c 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -3146,6 +3146,10 @@ public final class AutofillManager { if (afm == null) return null; final View view = afm.getClient().autofillClientFindViewByAutofillIdTraversal(id); + if (view == null) { + Log.w(TAG, "getViewCoordinates(" + id + "): could not find view"); + return null; + } final Rect windowVisibleDisplayFrame = new Rect(); view.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame); final int[] location = new int[2]; diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java index 019ebffccc13..5a27e94aa495 100644 --- a/core/java/android/view/contentcapture/ContentCaptureContext.java +++ b/core/java/android/view/contentcapture/ContentCaptureContext.java @@ -161,7 +161,7 @@ public final class ContentCaptureContext implements Parcelable { /** * Gets the context id. */ - @NonNull + @Nullable public LocusId getLocusId() { return mId; } diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java index 97ede862bfaa..03f1ec5821d0 100644 --- a/core/java/android/view/inspector/InspectableProperty.java +++ b/core/java/android/view/inspector/InspectableProperty.java @@ -87,21 +87,21 @@ public @interface InspectableProperty { * * Note that {@link #enumMapping()} cannot be used simultaneously with {@link #flagMapping()}. * - * @return An array of {@link EnumMap}, empty if not applicable + * @return An array of {@link EnumEntry}, empty if not applicable * @see android.annotation.IntDef */ - EnumMap[] enumMapping() default {}; + EnumEntry[] enumMapping() default {}; /** * For flags packed into primitive {int} properties, model the string names of the flags. * * Note that {@link #flagMapping()} cannot be used simultaneously with {@link #enumMapping()}. * - * @return An array of {@link FlagMap}, empty if not applicable + * @return An array of {@link FlagEntry}, empty if not applicable * @see android.annotation.IntDef * @see IntFlagMapping */ - FlagMap[] flagMapping() default {}; + FlagEntry[] flagMapping() default {}; /** @@ -113,7 +113,7 @@ public @interface InspectableProperty { @Target({TYPE}) @Retention(SOURCE) @TestApi - @interface EnumMap { + @interface EnumEntry { /** * The string name of this enumeration value. * @@ -138,7 +138,7 @@ public @interface InspectableProperty { @Target({TYPE}) @Retention(SOURCE) @TestApi - @interface FlagMap { + @interface FlagEntry { /** * The string name of this flag. * @@ -195,7 +195,7 @@ public @interface InspectableProperty { * * This is inferred if {@link #enumMapping()} is specified. * - * @see EnumMap + * @see EnumEntry * @hide */ @TestApi @@ -206,7 +206,7 @@ public @interface InspectableProperty { * * This is inferred if {@link #flagMapping()} is specified. * - * @see FlagMap + * @see FlagEntry * @hide */ @TestApi @@ -227,7 +227,7 @@ public @interface InspectableProperty { /** * Value packs gravity information. * - * This type is not inferred, and is non-trivial to represent using {@link FlagMap}. + * This type is not inferred, and is non-trivial to represent using {@link FlagEntry}. * * @see android.view.Gravity * @hide diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 494eb0358ab9..a46580dcc539 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -245,10 +245,11 @@ public abstract class WebSettings { /** * Used with {@link #setForceDark} * - * Enable force dark, dependent on the state of the WebView parent. If the WebView parent view - * is being automatically rendered in dark mode, then WebView content will be rendered so as to - * emulate a dark theme. WebViews that are not attached to the view hierarchy will not be - * inverted. + * Enable force dark dependent on the state of the WebView parent view. If the WebView parent + * view is being automatically force darkened + * (see: {@link android.view.View#setForceDarkAllowed}), then WebView content will be rendered + * so as to emulate a dark theme. WebViews that are not attached to the view hierarchy will not + * be inverted. */ public static final int FORCE_DARK_AUTO = 1; @@ -1466,6 +1467,8 @@ public abstract class WebSettings { /** * Set the force dark mode for this WebView. + * + * @param forceDark the force dark mode to set. */ public void setForceDark(@ForceDark int forceDark) { // Stub implementation to satisfy Roboelectrc shadows that don't override this yet. @@ -1474,6 +1477,8 @@ public abstract class WebSettings { /** * Get the force dark mode for this WebView. * + * The default force dark mode is {@link #FORCE_DARK_AUTO} + * * @return the currently set force dark mode. */ public @ForceDark int getForceDark() { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 034cabd5702e..26dba45666fc 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2292,9 +2292,9 @@ public class WebView extends AbsoluteLayout * @return the requested renderer priority policy. */ @InspectableProperty(hasAttributeId = false, enumMapping = { - @InspectableProperty.EnumMap(name = "waived", value = RENDERER_PRIORITY_WAIVED), - @InspectableProperty.EnumMap(name = "bound", value = RENDERER_PRIORITY_BOUND), - @InspectableProperty.EnumMap(name = "important", value = RENDERER_PRIORITY_IMPORTANT) + @InspectableProperty.EnumEntry(name = "waived", value = RENDERER_PRIORITY_WAIVED), + @InspectableProperty.EnumEntry(name = "bound", value = RENDERER_PRIORITY_BOUND), + @InspectableProperty.EnumEntry(name = "important", value = RENDERER_PRIORITY_IMPORTANT) }) @RendererPriority public int getRendererRequestedPriority() { diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 6d88530f29d9..4413585535f2 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -448,8 +448,9 @@ public final class WebViewFactory { Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()"); try { - initialApplication.getAssets().addAssetPathAsSharedLibrary( - webViewContext.getApplicationInfo().sourceDir); + for (String newAssetPath : webViewContext.getApplicationInfo().getAllApkPaths()) { + initialApplication.getAssets().addAssetPathAsSharedLibrary(newAssetPath); + } ClassLoader clazzLoader = webViewContext.getClassLoader(); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()"); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 24f1fb5cc352..4cb552d29c32 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -83,7 +83,7 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import android.view.inputmethod.InputMethodManager; import android.view.inspector.InspectableProperty; -import android.view.inspector.InspectableProperty.EnumMap; +import android.view.inspector.InspectableProperty.EnumEntry; import android.widget.RemoteViews.OnClickHandler; import com.android.internal.R; @@ -1221,10 +1221,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @return The current choice mode */ @InspectableProperty(enumMapping = { - @EnumMap(value = CHOICE_MODE_NONE, name = "none"), - @EnumMap(value = CHOICE_MODE_SINGLE, name = "singleChoice"), - @EnumMap(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"), - @EnumMap(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal") + @EnumEntry(value = CHOICE_MODE_NONE, name = "none"), + @EnumEntry(value = CHOICE_MODE_SINGLE, name = "singleChoice"), + @InspectableProperty.EnumEntry(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"), + @EnumEntry(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal") }) public int getChoiceMode() { return mChoiceMode; @@ -6293,9 +6293,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * {@link #TRANSCRIPT_MODE_ALWAYS_SCROLL} */ @InspectableProperty(enumMapping = { - @EnumMap(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"), - @EnumMap(value = TRANSCRIPT_MODE_NORMAL, name = "normal"), - @EnumMap(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll") + @EnumEntry(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"), + @EnumEntry(value = TRANSCRIPT_MODE_NORMAL, name = "normal"), + @EnumEntry(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll") }) public int getTranscriptMode() { return mTranscriptMode; diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index ecb846b1fcce..0c593be1ee7d 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -216,8 +216,8 @@ public class DatePicker extends FrameLayout { * @hide Visible for testing only. */ @InspectableProperty(name = "datePickerMode", enumMapping = { - @InspectableProperty.EnumMap(value = MODE_SPINNER, name = "spinner"), - @InspectableProperty.EnumMap(value = MODE_CALENDAR, name = "calendar") + @InspectableProperty.EnumEntry(value = MODE_SPINNER, name = "spinner"), + @InspectableProperty.EnumEntry(value = MODE_CALENDAR, name = "calendar") }) @DatePickerMode @TestApi diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index b6ec5f936fbd..c9ef038b78de 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -4984,9 +4984,6 @@ public class Editor { if (magnifierTopLeft == null) { return; } - final Rect surfaceInsets = - mTextView.getViewRootImpl().mWindowAttributes.surfaceInsets; - magnifierTopLeft.offset(-surfaceInsets.left, -surfaceInsets.top); final Rect magnifierRect = new Rect(magnifierTopLeft.x, magnifierTopLeft.y, magnifierTopLeft.x + mMagnifierAnimator.mMagnifier.getWidth(), magnifierTopLeft.y + mMagnifierAnimator.mMagnifier.getHeight()); diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 1c8bb0470e2e..8cda47dae39b 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -331,8 +331,8 @@ public class GridLayout extends ViewGroup { */ @Orientation @InspectableProperty(enumMapping = { - @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"), - @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical") + @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"), + @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical") }) public int getOrientation() { return mOrientation; @@ -510,8 +510,8 @@ public class GridLayout extends ViewGroup { */ @AlignmentMode @InspectableProperty(enumMapping = { - @InspectableProperty.EnumMap(value = ALIGN_BOUNDS, name = "alignBounds"), - @InspectableProperty.EnumMap(value = ALIGN_MARGINS, name = "alignMargins"), + @InspectableProperty.EnumEntry(value = ALIGN_BOUNDS, name = "alignBounds"), + @InspectableProperty.EnumEntry(value = ALIGN_MARGINS, name = "alignMargins"), }) public int getAlignmentMode() { return mAlignmentMode; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index f44c33178242..4e39a559c6ea 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -2174,11 +2174,11 @@ public class GridView extends AbsListView { @StretchMode @InspectableProperty(enumMapping = { - @InspectableProperty.EnumMap(value = NO_STRETCH, name = "none"), - @InspectableProperty.EnumMap(value = STRETCH_SPACING, name = "spacingWidth"), - @InspectableProperty.EnumMap( + @InspectableProperty.EnumEntry(value = NO_STRETCH, name = "none"), + @InspectableProperty.EnumEntry(value = STRETCH_SPACING, name = "spacingWidth"), + @InspectableProperty.EnumEntry( value = STRETCH_SPACING_UNIFORM, name = "spacingWidthUniform"), - @InspectableProperty.EnumMap(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"), + @InspectableProperty.EnumEntry(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"), }) public int getStretchMode() { return mStretchMode; diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index bdde4352d69d..a83e82699938 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -1850,8 +1850,8 @@ public class LinearLayout extends ViewGroup { */ @OrientationMode @InspectableProperty(enumMapping = { - @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"), - @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical") + @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"), + @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical") }) public int getOrientation() { return mOrientation; diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 50e883679eb9..08799cfb5d4c 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -471,13 +471,13 @@ public final class Magnifier { } /** - * Returns the top left coordinates of the magnifier, relative to the surface of the - * main application window. They will be determined by the coordinates of the last - * {@link #show(float, float)} or {@link #show(float, float, float, float)} call, adjusted - * to take into account any potential clamping behavior. The method can be used immediately - * after a #show call to find out where the magnifier will be positioned. However, the - * position of the magnifier will not be updated in the same frame due to the async - * copying of the content copying and of the magnifier rendering. + * Returns the top left coordinates of the magnifier, relative to the main application + * window. They will be determined by the coordinates of the last {@link #show(float, float)} + * or {@link #show(float, float, float, float)} call, adjusted to take into account any + * potential clamping behavior. The method can be used immediately after a #show + * call to find out where the magnifier will be positioned. However, the position of the + * magnifier will not be updated visually in the same frame, due to the async nature of + * the content copying and of the magnifier rendering. * The method will return {@code null} if #show has not yet been called, or if the last * operation performed was a #dismiss. * @@ -488,15 +488,18 @@ public final class Magnifier { if (mWindow == null) { return null; } - return new Point(getCurrentClampedWindowCoordinates()); + final Point position = getCurrentClampedWindowCoordinates(); + position.offset(-mParentSurface.mInsets.left, -mParentSurface.mInsets.top); + return new Point(position); } /** * Returns the top left coordinates of the magnifier source (i.e. the view region going to - * be magnified and copied to the magnifier), relative to the surface the content is copied - * from. The content will be copied: + * be magnified and copied to the magnifier), relative to the window or surface the content + * is copied from. The content will be copied: * - if the magnified view is a {@link SurfaceView}, from the surface backing it - * - otherwise, from the surface of the main application window + * - otherwise, from the surface backing the main application window, and the coordinates + * returned will be relative to the main application window * The method will return {@code null} if #show has not yet been called, or if the last * operation performed was a #dismiss. * @@ -507,7 +510,9 @@ public final class Magnifier { if (mWindow == null) { return null; } - return new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top); + final Point position = new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top); + position.offset(-mContentCopySurface.mInsets.left, -mContentCopySurface.mInsets.top); + return new Point(position); } /** @@ -531,7 +536,7 @@ public final class Magnifier { viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; validMainWindowSurface = new SurfaceInfo(viewRootImpl.getSurfaceControl(), mainWindowSurface, - surfaceWidth, surfaceHeight, true); + surfaceWidth, surfaceHeight, surfaceInsets, true); } } // Get the surface backing the magnified view, if it is a SurfaceView. @@ -544,7 +549,7 @@ public final class Magnifier { if (sc != null && sc.isValid()) { final Rect surfaceFrame = surfaceHolder.getSurfaceFrame(); validSurfaceViewSurface = new SurfaceInfo(sc, surfaceViewSurface, - surfaceFrame.right, surfaceFrame.bottom, false); + surfaceFrame.right, surfaceFrame.bottom, new Rect(), false); } } @@ -708,9 +713,13 @@ public final class Magnifier { final Rect windowBounds; if (mParentSurface.mIsMainWindowSurface) { final Insets systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); - windowBounds = new Rect(systemInsets.left, systemInsets.top, - mParentSurface.mWidth - systemInsets.right, - mParentSurface.mHeight - systemInsets.bottom); + windowBounds = new Rect( + systemInsets.left + mParentSurface.mInsets.left, + systemInsets.top + mParentSurface.mInsets.top, + mParentSurface.mWidth - systemInsets.right - mParentSurface.mInsets.right, + mParentSurface.mHeight - systemInsets.bottom + - mParentSurface.mInsets.bottom + ); } else { windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight); } @@ -725,21 +734,23 @@ public final class Magnifier { * Contains a surface and metadata corresponding to it. */ private static class SurfaceInfo { - public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, false); + public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, null, false); private Surface mSurface; private SurfaceControl mSurfaceControl; private int mWidth; private int mHeight; + private Rect mInsets; private boolean mIsMainWindowSurface; SurfaceInfo(final SurfaceControl surfaceControl, final Surface surface, - final int width, final int height, + final int width, final int height, final Rect insets, final boolean isMainWindowSurface) { mSurfaceControl = surfaceControl; mSurface = surface; mWidth = width; mHeight = height; + mInsets = insets; mIsMainWindowSurface = isMainWindowSurface; } } diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING new file mode 100644 index 000000000000..ee378ff72218 --- /dev/null +++ b/core/java/android/widget/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsWidgetTestCases", + "options": [ + { + "instrumentation-arg": "size:=small" + } + ] + } + ] +} diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 04bcb1451b61..a5a1a80cca88 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -173,8 +173,8 @@ import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.view.inspector.InspectableProperty; -import android.view.inspector.InspectableProperty.EnumMap; -import android.view.inspector.InspectableProperty.FlagMap; +import android.view.inspector.InspectableProperty.EnumEntry; +import android.view.inspector.InspectableProperty.FlagEntry; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassificationContext; import android.view.textclassifier.TextClassificationManager; @@ -1900,8 +1900,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @see #setAutoSizeTextTypeUniformWithPresetSizes(int[], int) */ @InspectableProperty(enumMapping = { - @EnumMap(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE), - @EnumMap(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM) + @EnumEntry(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE), + @EnumEntry(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM) }) @AutoSizeTextType public int getAutoSizeTextType() { @@ -3527,10 +3527,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_autoLink */ @InspectableProperty(name = "autoLink", flagMapping = { - @FlagMap(name = "web", target = Linkify.WEB_URLS), - @FlagMap(name = "email", target = Linkify.EMAIL_ADDRESSES), - @FlagMap(name = "phone", target = Linkify.PHONE_NUMBERS), - @FlagMap(name = "map", target = Linkify.MAP_ADDRESSES) + @FlagEntry(name = "web", target = Linkify.WEB_URLS), + @FlagEntry(name = "email", target = Linkify.EMAIL_ADDRESSES), + @FlagEntry(name = "phone", target = Linkify.PHONE_NUMBERS), + @FlagEntry(name = "map", target = Linkify.MAP_ADDRESSES) }) public final int getAutoLinkMask() { return mAutoLinkMask; @@ -4515,9 +4515,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @see #setBreakStrategy(int) */ @InspectableProperty(enumMapping = { - @EnumMap(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE), - @EnumMap(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY), - @EnumMap(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED) + @EnumEntry(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE), + @EnumEntry(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY), + @EnumEntry(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED) }) @Layout.BreakStrategy public int getBreakStrategy() { @@ -4566,9 +4566,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @see #setHyphenationFrequency(int) */ @InspectableProperty(enumMapping = { - @EnumMap(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE), - @EnumMap(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL), - @EnumMap(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL) + @EnumEntry(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE), + @EnumEntry(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL), + @EnumEntry(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL) }) @Layout.HyphenationFrequency public int getHyphenationFrequency() { @@ -4628,8 +4628,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @see #setJustificationMode(int) */ @InspectableProperty(enumMapping = { - @EnumMap(name = "none", value = Layout.JUSTIFICATION_MODE_NONE), - @EnumMap(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD) + @EnumEntry(name = "none", value = Layout.JUSTIFICATION_MODE_NONE), + @EnumEntry(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD) }) public @Layout.JustificationMode int getJustificationMode() { return mJustificationMode; @@ -6667,142 +6667,142 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @see android.text.InputType */ @InspectableProperty(flagMapping = { - @FlagMap(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL), - @FlagMap( + @FlagEntry(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL), + @FlagEntry( name = "text", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL), - @FlagMap( + @FlagEntry( name = "textUri", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI), - @FlagMap( + @FlagEntry( name = "textEmailAddress", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS), - @FlagMap( + @FlagEntry( name = "textEmailSubject", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT), - @FlagMap( + @FlagEntry( name = "textShortMessage", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE), - @FlagMap( + @FlagEntry( name = "textLongMessage", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE), - @FlagMap( + @FlagEntry( name = "textPersonName", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PERSON_NAME), - @FlagMap( + @FlagEntry( name = "textPostalAddress", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS), - @FlagMap( + @FlagEntry( name = "textPassword", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD), - @FlagMap( + @FlagEntry( name = "textVisiblePassword", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD), - @FlagMap( + @FlagEntry( name = "textWebEditText", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT), - @FlagMap( + @FlagEntry( name = "textFilter", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER), - @FlagMap( + @FlagEntry( name = "textPhonetic", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PHONETIC), - @FlagMap( + @FlagEntry( name = "textWebEmailAddress", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS), - @FlagMap( + @FlagEntry( name = "textWebPassword", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD), - @FlagMap( + @FlagEntry( name = "number", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL), - @FlagMap( + @FlagEntry( name = "numberPassword", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD), - @FlagMap( + @FlagEntry( name = "phone", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_PHONE), - @FlagMap( + @FlagEntry( name = "datetime", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_NORMAL), - @FlagMap( + @FlagEntry( name = "date", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE), - @FlagMap( + @FlagEntry( name = "time", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION, target = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME), - @FlagMap( + @FlagEntry( name = "textCapCharacters", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS), - @FlagMap( + @FlagEntry( name = "textCapWords", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_WORDS), - @FlagMap( + @FlagEntry( name = "textCapSentences", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES), - @FlagMap( + @FlagEntry( name = "textAutoCorrect", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT), - @FlagMap( + @FlagEntry( name = "textAutoComplete", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE), - @FlagMap( + @FlagEntry( name = "textMultiLine", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE), - @FlagMap( + @FlagEntry( name = "textImeMultiLine", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE), - @FlagMap( + @FlagEntry( name = "textNoSuggestions", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS), - @FlagMap( + @FlagEntry( name = "numberSigned", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED), - @FlagMap( + @FlagEntry( name = "numberDecimal", mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS, target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL), @@ -6832,49 +6832,51 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @see EditorInfo */ @InspectableProperty(flagMapping = { - @FlagMap(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL), - @FlagMap( + @FlagEntry(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL), + @FlagEntry( name = "actionUnspecified", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_UNSPECIFIED), - @FlagMap( + @FlagEntry( name = "actionNone", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_NONE), - @FlagMap( + @FlagEntry( name = "actionGo", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_GO), - @FlagMap( + @FlagEntry( name = "actionSearch", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_SEARCH), - @FlagMap( + @FlagEntry( name = "actionSend", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_SEND), - @FlagMap( + @FlagEntry( name = "actionNext", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_NEXT), - @FlagMap( + @FlagEntry( name = "actionDone", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_DONE), - @FlagMap( + @FlagEntry( name = "actionPrevious", mask = EditorInfo.IME_MASK_ACTION, target = EditorInfo.IME_ACTION_PREVIOUS), - @FlagMap(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII), - @FlagMap(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT), - @FlagMap(name = "flagNavigatePrevious", target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS), - @FlagMap( + @FlagEntry(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII), + @FlagEntry(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT), + @FlagEntry( + name = "flagNavigatePrevious", + target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS), + @FlagEntry( name = "flagNoAccessoryAction", target = EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION), - @FlagMap(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION), - @FlagMap(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI), - @FlagMap(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN), - @FlagMap( + @FlagEntry(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION), + @FlagEntry(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI), + @FlagEntry(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN), + @FlagEntry( name = "flagNoPersonalizedLearning", target = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING), }) diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index c7a298016d44..8a5d5312bd7b 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -169,8 +169,8 @@ public class TimePicker extends FrameLayout { @TimePickerMode @TestApi @InspectableProperty(name = "timePickerMode", enumMapping = { - @InspectableProperty.EnumMap(name = "clock", value = MODE_CLOCK), - @InspectableProperty.EnumMap(name = "spinner", value = MODE_SPINNER) + @InspectableProperty.EnumEntry(name = "clock", value = MODE_CLOCK), + @InspectableProperty.EnumEntry(name = "spinner", value = MODE_SPINNER) }) public int getMode() { return mMode; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index f250666012f6..faf0c7dbed37 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -680,7 +680,7 @@ public class ChooserActivity extends ResolverActivity { & DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0; } } - } catch (SecurityException e) { + } catch (SecurityException | NullPointerException e) { Log.w(TAG, "Error loading file preview", e); } @@ -918,6 +918,8 @@ public class ChooserActivity extends ResolverActivity { if (isSendAction(in)) { in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + + in.fixUris(getUserId()); } } diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java index eb881def5d67..5c144d3b5752 100644 --- a/core/java/com/android/internal/infra/AbstractRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractRemoteService.java @@ -577,6 +577,12 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I protected boolean isFinal() { return false; } + + protected boolean isRequestCompleted() { + synchronized (mLock) { + return mCompleted; + } + } } /** diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index 4773e168fffa..3205b5aef281 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -20,12 +20,16 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; +import android.graphics.Path; import android.graphics.RectF; +import android.graphics.Region; import android.hardware.input.InputManager; import android.hardware.input.InputManager.InputDeviceListener; +import android.os.RemoteException; import android.os.SystemProperties; import android.util.Log; import android.util.Slog; +import android.view.ISystemGestureExclusionListener; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; @@ -34,6 +38,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowInsets; +import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicyConstants.PointerEventListener; import java.util.ArrayList; @@ -124,12 +129,16 @@ public class PointerLocationView extends View implements InputDeviceListener, private int mActivePointerId; private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); private final PointerCoords mTempCoords = new PointerCoords(); - + + private final Region mSystemGestureExclusion = new Region(); + private final Path mSystemGestureExclusionPath = new Path(); + private final Paint mSystemGestureExclusionPaint; + private final VelocityTracker mVelocity; private final VelocityTracker mAltVelocity; private final FasterStringBuilder mText = new FasterStringBuilder(); - + private boolean mPrintCoords = true; public PointerLocationView(Context c) { @@ -168,7 +177,11 @@ public class PointerLocationView extends View implements InputDeviceListener, mPathPaint.setARGB(255, 0, 96, 255); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(1); - + + mSystemGestureExclusionPaint = new Paint(); + mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0); + mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE); + PointerState ps = new PointerState(); mPointers.add(ps); mActivePointerId = 0; @@ -236,6 +249,12 @@ public class PointerLocationView extends View implements InputDeviceListener, final int NP = mPointers.size(); + if (!mSystemGestureExclusion.isEmpty()) { + mSystemGestureExclusionPath.reset(); + mSystemGestureExclusion.getBoundaryPath(mSystemGestureExclusionPath); + canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint); + } + // Labels if (mActivePointerId >= 0) { final PointerState ps = mPointers.get(mActivePointerId); @@ -719,6 +738,12 @@ public class PointerLocationView extends View implements InputDeviceListener, super.onAttachedToWindow(); mIm.registerInputDeviceListener(this, getHandler()); + try { + WindowManagerGlobal.getWindowManagerService().registerSystemGestureExclusionListener( + mSystemGestureExclusionListener, mContext.getDisplayId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } logInputDevices(); } @@ -727,6 +752,12 @@ public class PointerLocationView extends View implements InputDeviceListener, super.onDetachedFromWindow(); mIm.unregisterInputDeviceListener(this); + try { + WindowManagerGlobal.getWindowManagerService().unregisterSystemGestureExclusionListener( + mSystemGestureExclusionListener, mContext.getDisplayId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } @Override @@ -876,4 +907,17 @@ public class PointerLocationView extends View implements InputDeviceListener, return oldLength; } } + + private ISystemGestureExclusionListener mSystemGestureExclusionListener = + new ISystemGestureExclusionListener.Stub() { + @Override + public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) { + Region exclusion = Region.obtain(systemGestureExclusion); + getHandler().post(() -> { + mSystemGestureExclusion.set(exclusion); + exclusion.recycle(); + invalidate(); + }); + } + }; } diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 7ad922312fa9..f03740725fe1 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2305,4 +2305,8 @@ enum PageId { // Open: Settings > Special App Access > Do not disturb control for app ZEN_ACCESS_DETAIL = 1692; + + // OPEN: Settings > Face > Remove face + // OS: Q + DIALOG_FACE_REMOVE = 1693; } diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto index 8fce94edb104..9bf1825a8da6 100644 --- a/core/proto/android/server/powermanagerservice.proto +++ b/core/proto/android/server/powermanagerservice.proto @@ -318,6 +318,16 @@ message BatterySaverStateMachineProto { // Whether battery saver is enabled. optional bool enabled = 1; + enum StateEnum { + STATE_UNKNOWN = 0; + STATE_OFF = 1; + STATE_MANUAL_ON = 2; + STATE_AUTOMATIC_ON = 3; + STATE_OFF_AUTOMATIC_SNOOZED = 4; + STATE_PENDING_STICKY_ON = 5; + } + optional StateEnum state = 18; + // Whether full battery saver is enabled. optional bool is_full_enabled = 14; @@ -337,8 +347,7 @@ message BatterySaverStateMachineProto { // Whether battery status has been set at least once. optional bool battery_status_set = 4; - // Whether automatic battery saver has been canceled by the user. - optional bool battery_saver_snoozing = 5; + reserved 5; // battery_saver_snoozing // Whether the device is connected to any power source. optional bool is_powered = 6; @@ -373,5 +382,5 @@ message BatterySaverStateMachineProto { // using elapsed realtime as the timebase. optional int64 last_adaptive_battery_saver_changed_externally_elapsed = 17; - // Next tag: 18 + // Next tag: 19 } diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index c08d7cafd9cc..4ef26dd59240 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -66,6 +66,10 @@ message NotificationRecordProto { optional bool can_show_light = 8; optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ]; optional sint32 importance = 10; + // The package the notification was posted for. + optional string package = 11; + // The package that posted the notification. It might not be the same as package. + optional string delegate_package = 12; } message ListenersDisablingEffectsProto { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c7417bffb790..efc6ad017bb1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3929,6 +3929,10 @@ <permission android:name="android.permission.MANAGE_ROLLBACKS" android:protectionLevel="signature|verifier" /> + <!-- @SystemApi @TestApi @hide Allows testing apk level rollbacks. --> + <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" + android:protectionLevel="signature" /> + <!-- @SystemApi @hide Allows an application to mark other applications as harmful --> <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS" android:protectionLevel="signature|verifier" /> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 743496fdffb5..9d48fe384f3f 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8108,7 +8108,7 @@ <!-- Use <code>autofill-service</code> as the root tag of the XML resource that describes a {@link android.service.autofill.AutofillService}, which is referenced from its - {@link android.service.autofill#SERVICE_META_DATA} meta-data entry. + {@link android.service.autofill.AutofillService#SERVICE_META_DATA} meta-data entry. --> <declare-styleable name="AutofillService"> <!-- Fully qualified class name of an activity that allows the user to modify @@ -8134,6 +8134,23 @@ </declare-styleable> <!-- =============================== --> + <!-- Content Capture attributes --> + <!-- =============================== --> + <eat-comment /> + + <!-- Use <code>content-capture-service</code> as the root tag of the XML resource that describes + a {@link android.service.contentcapture.ContentCaptureService}, which is referenced from + its {@link android.service.contentcapture.ContentCaptureService#SERVICE_META_DATA} + meta-data entry. + @hide @SystemApi + --> + <declare-styleable name="ContentCaptureService"> + <!-- Fully qualified class name of an activity that allows the user to modify + the settings for this service. --> + <attr name="settingsActivity" /> + </declare-styleable> + + <!-- =============================== --> <!-- Contacts meta-data attributes --> <!-- =============================== --> <eat-comment /> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index dbea13ec7539..fe2c6655a6ed 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -118,8 +118,11 @@ <attr name="manageSpaceActivity" format="string" /> <!-- Option to let applications specify that user data can/cannot be - cleared by the user in Settings. This flag is turned on by default. - <em>This attribute is usable only by applications + cleared. This flag is turned on by default. + <p>Starting from API level 29 this flag only controls if the user can + clear app data from Settings. To control clearing the data after a + failed restore use allowClearUserDataOnFailedRestore flag. + <p><em>This attribute is usable only by applications included in the system image. Third-party apps cannot use it.</em> --> <attr name="allowClearUserData" format="boolean" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 2b13c4e23602..74970e810181 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1538,43 +1538,45 @@ <string name="permdesc_useFaceAuthentication">Allows the app to use face authentication hardware for authentication</string> <!-- Message shown during face acquisition when the face cannot be recognized [CHAR LIMIT=50] --> - <string name="face_acquired_insufficient">Couldn\u2019t process face. Please try again.</string> + <string name="face_acquired_insufficient">Couldn\u2019t capture accurate face data. Try again.</string> <!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] --> - <string name="face_acquired_too_bright">Face is too bright. Please try in lower light.</string> + <string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string> <!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] --> - <string name="face_acquired_too_dark">Face is too dark. Please uncover light source.</string> + <string name="face_acquired_too_dark">Too dark. Try brighter lighting.</string> <!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_close">Please move sensor farther from face.</string> + <string name="face_acquired_too_close">Move phone farther away.</string> <!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_far">Please bring sensor closer to face.</string> + <string name="face_acquired_too_far">Move phone closer.</string> <!-- Message shown during face acquisition when the user is too high relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_high">Please move sensor higher.</string> + <string name="face_acquired_too_high">Move phone higher.</string> <!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_low">Please move sensor lower.</string> + <string name="face_acquired_too_low">Move phone lower.</string> <!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_right">Please move sensor to the right.</string> + <string name="face_acquired_too_right">Move phone to the right.</string> <!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_left">Please move sensor to the left.</string> + <string name="face_acquired_too_left">Move phone to the left.</string> <!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] --> - <string name="face_acquired_poor_gaze">Please look at the sensor.</string> + <string name="face_acquired_poor_gaze">Look at the screen with your eyes open.</string> <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] --> - <string name="face_acquired_not_detected">No face detected.</string> + <string name="face_acquired_not_detected">Can\u2019t see your face. Look at the phone.</string> <!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] --> - <string name="face_acquired_too_much_motion">Too much motion.</string> + <string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string> <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] --> <string name="face_acquired_recalibrate">Please re-enroll your face.</string> <!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] --> - <string name="face_acquired_too_different">Different face detected.</string> + <string name="face_acquired_too_different">No longer able to recognize face. Try again.</string> <!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] --> <string name="face_acquired_too_similar">Too similar, please change your pose.</string> <!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] --> - <string name="face_acquired_pan_too_extreme">Please look more directly at the camera.</string> + <string name="face_acquired_pan_too_extreme">Please look more directly at the screen.</string> <!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] --> - <string name="face_acquired_tilt_too_extreme">Please look more directly at the camera.</string> + <string name="face_acquired_tilt_too_extreme">Please look more directly at the screen.</string> <!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] --> <string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string> <!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] --> - <string name="face_acquired_obscured">Please uncover your face.</string> + <string name="face_acquired_obscured">Clear the space between your head and the phone.</string> + <!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=50] --> + <string name="face_acquired_sensor_dirty">Please clean the camera.</string> <!-- Array containing custom messages shown during face acquisition from vendor. Vendor is expected to add and translate these strings --> <string-array name="face_acquired_vendor"> </string-array> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e5fc104ddb2d..17ccc31179f9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2546,6 +2546,7 @@ <java-symbol type="string" name="face_acquired_tilt_too_extreme" /> <java-symbol type="string" name="face_acquired_roll_too_extreme" /> <java-symbol type="string" name="face_acquired_obscured" /> + <java-symbol type="string" name="face_acquired_sensor_dirty" /> <java-symbol type="array" name="face_acquired_vendor" /> <java-symbol type="string" name="face_name_template" /> <java-symbol type="string" name="face_authenticated_no_confirmation_required" /> diff --git a/core/tests/overlaytests/device/assets/package-name.txt b/core/tests/overlaytests/device/assets/package-name.txt new file mode 100644 index 000000000000..809443818f06 --- /dev/null +++ b/core/tests/overlaytests/device/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java index 91fcdbbb18ce..f86743a2fdbc 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java @@ -17,9 +17,12 @@ package com.android.overlaytest; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.UiAutomation; +import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -30,6 +33,8 @@ import android.util.Xml; import androidx.test.InstrumentationRegistry; +import com.android.internal.util.ArrayUtils; + import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -291,6 +296,33 @@ public abstract class OverlayBaseTest { assertEquals(getExpected(no, so, mo), actual); } + @Test + public void testAssetsNotPossibleToOverlay() throws Throwable { + final AssetManager am = mResources.getAssets(); + + // AssetManager#list will include assets from all loaded non-overlay + // APKs, including the framework; framework-res.apk contains at least + // assets/{images,webkit}. Rather than checking the list, verify that + // assets only present in overlays are never part of the list. + String[] files = am.list(""); + assertTrue(ArrayUtils.contains(files, "package-name.txt")); + assertFalse(ArrayUtils.contains(files, "foo.txt")); + assertFalse(ArrayUtils.contains(files, "bar.txt")); + + String contents = null; + try (InputStream is = am.open("package-name.txt")) { + final BufferedReader reader = new BufferedReader( + new InputStreamReader(is, StandardCharsets.UTF_8)); + StringBuilder str = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + str.append(line); + } + contents = str.toString(); + } + assertEquals("com.android.overlaytest", contents); + } + /* * testMatrix* tests * diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt new file mode 100644 index 000000000000..257cc5642cb1 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt @@ -0,0 +1 @@ +foo diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt new file mode 100644 index 000000000000..087cb96b767f --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_one diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt new file mode 100644 index 000000000000..5716ca5987cb --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt @@ -0,0 +1 @@ +bar diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt new file mode 100644 index 000000000000..13185654df21 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_two diff --git a/docs/html/reference/images/text/style/linebackgroundspan.png b/docs/html/reference/images/text/style/linebackgroundspan.png Binary files differnew file mode 100644 index 000000000000..37d525331e3d --- /dev/null +++ b/docs/html/reference/images/text/style/linebackgroundspan.png diff --git a/docs/html/reference/images/text/style/lineheightspan.png b/docs/html/reference/images/text/style/lineheightspan.png Binary files differnew file mode 100644 index 000000000000..18f575392b63 --- /dev/null +++ b/docs/html/reference/images/text/style/lineheightspan.png diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 0d5233880674..9c4b5e8b0165 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1809,6 +1809,45 @@ public abstract class ColorSpace { } /** + * <p>Computes the chromaticity coordinates of a specified correlated color + * temperature (CCT) on the Planckian locus. The specified CCT must be + * greater than 0. A meaningful CCT range is [1667, 25000].</p> + * + * <p>The transform is computed using the methods in Kang et + * al., <i>Design of Advanced Color - Temperature Control System for HDTV + * Applications</i>, Journal of Korean Physical Society 41, 865-871 + * (2002).</p> + * + * @param cct The correlated color temperature, in Kelvin + * @return Corresponding XYZ values + * @throws IllegalArgumentException If cct is invalid + * + * @hide + */ + @NonNull + @Size(3) + public static float[] cctToXyz(@IntRange(from = 1) int cct) { + if (cct < 1) { + throw new IllegalArgumentException("Temperature must be greater than 0"); + } + + final float icct = 1e3f / cct; + final float icct2 = icct * icct; + final float x = cct <= 4000.0f ? + 0.179910f + 0.8776956f * icct - 0.2343589f * icct2 - 0.2661239f * icct2 * icct : + 0.240390f + 0.2226347f * icct + 2.1070379f * icct2 - 3.0258469f * icct2 * icct; + + final float x2 = x * x; + final float y = cct <= 2222.0f ? + -0.20219683f + 2.18555832f * x - 1.34811020f * x2 - 1.1063814f * x2 * x : + cct <= 4000.0f ? + -0.16748867f + 2.09137015f * x - 1.37418593f * x2 - 0.9549476f * x2 * x : + -0.37001483f + 3.75112997f * x - 5.8733867f * x2 + 3.0817580f * x2 * x; + + return xyYToXyz(new float[] {x, y}); + } + + /** * <p>Computes the chromaticity coordinates of a CIE series D illuminant * from the specified correlated color temperature (CCT). The specified CCT * must be greater than 0. A meaningful CCT range is [4000, 25000].</p> diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 9995f1e73018..c8b361bbff2f 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -33,7 +33,6 @@ import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; import android.os.Build; -import android.os.Build.VERSION_CODES; import android.os.ParcelFileDescriptor; import android.provider.FontRequest; import android.provider.FontsContract; @@ -48,7 +47,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import dalvik.annotation.optimization.CriticalNative; -import dalvik.system.VMRuntime; import libcore.util.NativeAllocationRegistry; @@ -266,16 +264,7 @@ public class Typeface { if (familyBuilder == null) { familyBuilder = new FontFamily.Builder(fontBuilder.build()); } else { - try { - familyBuilder.addFont(fontBuilder.build()); - } catch (IllegalArgumentException e) { - if (VMRuntime.getRuntime().getTargetSdkVersion() <= VERSION_CODES.P) { - // Surpress the IllegalArgumentException for keeping the backward - // compatibility. - continue; - } - throw e; - } + familyBuilder.addFont(fontBuilder.build()); } } if (familyBuilder == null) { @@ -297,6 +286,10 @@ public class Typeface { typeface = new Typeface.CustomFallbackBuilder(family) .setStyle(bestFont.getStyle()) .build(); + } catch (IllegalArgumentException e) { + // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion + // thrown by native code and returns null. + return null; } catch (IOException e) { typeface = Typeface.DEFAULT; } diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index 105af6e829f8..51c42520ccc9 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -16,7 +16,6 @@ package android.security.keystore; -import libcore.util.EmptyArray; import android.security.Credentials; import android.security.GateKeeper; import android.security.KeyStore; @@ -31,6 +30,8 @@ import android.security.keystore.SecureKeyImportUnavailableException; import android.security.keystore.WrappedKeyEntry; import android.util.Log; +import libcore.util.EmptyArray; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -123,7 +124,14 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { final Certificate[] caList; - final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid); + // Suppress the key not found warning for this call. It seems that this error is exclusively + // being thrown when there is a self signed certificate chain, so when the keystore service + // attempts to query for the CA details, it obviously fails to find them and returns a + // key not found exception. This is WAI, and throwing a stack trace here can be very + // misleading since the trace is not clear. + final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, + mUid, + true /* suppressKeyNotFoundWarning */); if (caBytes != null) { final Collection<X509Certificate> caChain = toCertificates(caBytes); diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp index c512a6b06ed1..9a95fdf80cb5 100644 --- a/libs/androidfw/Asset.cpp +++ b/libs/androidfw/Asset.cpp @@ -292,8 +292,10 @@ Asset::Asset(void) pAsset = new _FileAsset; result = pAsset->openChunk(dataMap); - if (result != NO_ERROR) + if (result != NO_ERROR) { + delete pAsset; return NULL; + } pAsset->mAccessMode = mode; return pAsset; diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index d74f27cca200..951970464bfe 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -310,6 +310,9 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con // Start from the back. for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) { const ApkAssets* apk_assets = *iter; + if (apk_assets->IsOverlay()) { + continue; + } auto func = [&](const StringPiece& name, FileType type) { AssetDir::FileInfo info; @@ -336,6 +339,13 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, Asset::AccessMode mode, ApkAssetsCookie* out_cookie) const { for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) { + // Prevent RRO from modifying assets and other entries accessed by file + // path. Explicitly asking for a path in a given package (denoted by a + // cookie) is still OK. + if (apk_assets_[i]->IsOverlay()) { + continue; + } + std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode); if (asset) { if (out_cookie != nullptr) { diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index db2d0382bcf6..35bbb5804df4 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -80,6 +80,10 @@ class ApkAssets { return loaded_arsc_.get(); } + inline bool IsOverlay() const { + return idmap_asset_.get() != nullptr; + } + private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index aeeb32c4620a..8f7e8142e735 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -18,6 +18,7 @@ #include "hwui/Bitmap.h" #include "renderthread/EglManager.h" +#include "renderthread/VulkanManager.h" #include "thread/ThreadBase.h" #include "utils/TimeUtils.h" @@ -25,7 +26,9 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <GLES3/gl3.h> +#include <GrContext.h> #include <SkCanvas.h> +#include <SkImage.h> #include <utils/GLUtils.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> @@ -33,58 +36,247 @@ namespace android::uirenderer { -static std::mutex sLock{}; -static sp<ThreadBase> sUploadThread = nullptr; -static renderthread::EglManager sEglManager; -static int sPendingUploads = 0; -static nsecs_t sLastUpload = 0; +class AHBUploader; +// This helper uploader classes allows us to upload using either EGL or Vulkan using the same +// interface. +static sp<AHBUploader> sUploader = nullptr; -static bool shouldTimeOutLocked() { - nsecs_t durationSince = systemTime() - sLastUpload; - return durationSince > 2000_ms; -} +struct FormatInfo { + PixelFormat pixelFormat; + GLint format, type; + VkFormat vkFormat; + bool isSupported = false; + bool valid = true; +}; -static void checkIdleTimeout() { - std::lock_guard _lock{sLock}; - if (sPendingUploads == 0 && shouldTimeOutLocked()) { - sEglManager.destroy(); - } else { - sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout); +class AHBUploader : public RefBase { +public: + virtual ~AHBUploader() {} + + // Called to start creation of the Vulkan and EGL contexts on another thread before we actually + // need to do an upload. + void initialize() { + onInitialize(); } -} -static void beginUpload() { - std::lock_guard _lock{sLock}; - sPendingUploads++; + void destroy() { + std::lock_guard _lock{mLock}; + LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress"); + if (mUploadThread) { + mUploadThread->requestExit(); + mUploadThread->join(); + mUploadThread = nullptr; + } + onDestroy(); + } + + bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp<GraphicBuffer> graphicBuffer) { + ATRACE_CALL(); + beginUpload(); + bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer); + endUpload(); + return result; + } + + void postIdleTimeoutCheck() { + mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); }); + } - if (!sUploadThread) { - sUploadThread = new ThreadBase{}; +protected: + std::mutex mLock; + sp<ThreadBase> mUploadThread = nullptr; + +private: + virtual void onInitialize() = 0; + virtual void onIdle() = 0; + virtual void onDestroy() = 0; + + virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp<GraphicBuffer> graphicBuffer) = 0; + virtual void onBeginUpload() = 0; + + bool shouldTimeOutLocked() { + nsecs_t durationSince = systemTime() - mLastUpload; + return durationSince > 2000_ms; } - if (!sUploadThread->isRunning()) { - sUploadThread->start("GrallocUploadThread"); + void idleTimeoutCheck() { + std::lock_guard _lock{mLock}; + if (mPendingUploads == 0 && shouldTimeOutLocked()) { + onIdle(); + } else { + this->postIdleTimeoutCheck(); + } } - if (!sEglManager.hasEglContext()) { - sUploadThread->queue().runSync([]() { - sEglManager.initialize(); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + void beginUpload() { + std::lock_guard _lock{mLock}; + mPendingUploads++; + + if (!mUploadThread) { + mUploadThread = new ThreadBase{}; + } + if (!mUploadThread->isRunning()) { + mUploadThread->start("GrallocUploadThread"); + } + + onBeginUpload(); + } + + void endUpload() { + std::lock_guard _lock{mLock}; + mPendingUploads--; + mLastUpload = systemTime(); + } + + int mPendingUploads = 0; + nsecs_t mLastUpload = 0; +}; + +#define FENCE_TIMEOUT 2000000000 + +class EGLUploader : public AHBUploader { +private: + void onInitialize() override {} + void onDestroy() override { + mEglManager.destroy(); + } + void onIdle() override { + mEglManager.destroy(); + } + + void onBeginUpload() override { + if (!mEglManager.hasEglContext()) { + mUploadThread->queue().runSync([this]() { + this->mEglManager.initialize(); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + }); + + this->postIdleTimeoutCheck(); + } + } + + + EGLDisplay getUploadEglDisplay() { + std::lock_guard _lock{mLock}; + LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?"); + return mEglManager.eglDisplay(); + } + + bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp<GraphicBuffer> graphicBuffer) override { + ATRACE_CALL(); + + EGLDisplay display = getUploadEglDisplay(); + + LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", + uirenderer::renderthread::EglManager::eglErrorString()); + // We use an EGLImage to access the content of the GraphicBuffer + // The EGL image is later bound to a 2D texture + EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); + AutoEglImage autoImage(display, clientBuffer); + if (autoImage.image == EGL_NO_IMAGE_KHR) { + ALOGW("Could not create EGL image, err =%s", + uirenderer::renderthread::EglManager::eglErrorString()); + return false; + } + + { + ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); + EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR { + AutoSkiaGlTexture glTexture; + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); + GL_CHECKPOINT(MODERATE); + + // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we + // provide. + // But asynchronous in sense that driver may upload texture onto hardware buffer + // when we first use it in drawing + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), + format.format, format.type, bitmap.getPixels()); + GL_CHECKPOINT(MODERATE); + + EGLSyncKHR uploadFence = + eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); + LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, + "Could not create sync fence %#x", eglGetError()); + glFlush(); + return uploadFence; + }); + + EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT); + LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, + "Failed to wait for the fence %#x", eglGetError()); + + eglDestroySyncKHR(display, fence); + } + return true; + } + + renderthread::EglManager mEglManager; +}; + +class VkUploader : public AHBUploader { +private: + void onInitialize() override { + std::lock_guard _lock{mLock}; + if (!mUploadThread) { + mUploadThread = new ThreadBase{}; + } + if (!mUploadThread->isRunning()) { + mUploadThread->start("GrallocUploadThread"); + } + + mUploadThread->queue().post([this]() { + std::lock_guard _lock{mVkLock}; + if (!mVulkanManager.hasVkContext()) { + mVulkanManager.initialize(); + } }); - sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout); } -} + void onDestroy() override { + mGrContext.reset(); + mVulkanManager.destroy(); + } + void onIdle() override { + mGrContext.reset(); + } -static void endUpload() { - std::lock_guard _lock{sLock}; - sPendingUploads--; - sLastUpload = systemTime(); -} + void onBeginUpload() override { + { + std::lock_guard _lock{mVkLock}; + if (!mVulkanManager.hasVkContext()) { + LOG_ALWAYS_FATAL_IF(mGrContext, + "GrContext exists with no VulkanManager for vulkan uploads"); + mUploadThread->queue().runSync([this]() { + mVulkanManager.initialize(); + }); + } + } + if (!mGrContext) { + GrContextOptions options; + mGrContext = mVulkanManager.createContext(options); + LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads"); + this->postIdleTimeoutCheck(); + } + } -static EGLDisplay getUploadEglDisplay() { - std::lock_guard _lock{sLock}; - LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?"); - return sEglManager.eglDisplay(); -} + bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format, + sp<GraphicBuffer> graphicBuffer) override { + ATRACE_CALL(); + + std::lock_guard _lock{mLock}; + + sk_sp<SkImage> image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), + bitmap.pixmap(), reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get())); + return (image.get() != nullptr); + } + + sk_sp<GrContext> mGrContext; + renderthread::VulkanManager mVulkanManager; + std::mutex mVkLock; +}; bool HardwareBitmapUploader::hasFP16Support() { static std::once_flag sOnce; @@ -105,16 +297,7 @@ bool HardwareBitmapUploader::hasFP16Support() { return hasFP16Support; } -#define FENCE_TIMEOUT 2000000000 - -struct FormatInfo { - PixelFormat pixelFormat; - GLint format, type; - bool isSupported = false; - bool valid = true; -}; - -static FormatInfo determineFormat(const SkBitmap& skBitmap) { +static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) { FormatInfo formatInfo; switch (skBitmap.info().colorType()) { case kRGBA_8888_SkColorType: @@ -124,15 +307,18 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap) { formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; formatInfo.format = GL_RGBA; formatInfo.type = GL_UNSIGNED_BYTE; + formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; break; case kRGBA_F16_SkColorType: formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support(); if (formatInfo.isSupported) { formatInfo.type = GL_HALF_FLOAT; formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; + formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT; } else { formatInfo.type = GL_UNSIGNED_BYTE; formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; } formatInfo.format = GL_RGBA; break; @@ -141,12 +327,14 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap) { formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565; formatInfo.format = GL_RGB; formatInfo.type = GL_UNSIGNED_SHORT_5_6_5; + formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16; break; case kGray_8_SkColorType: - formatInfo.isSupported = true; + formatInfo.isSupported = usingGL; formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; formatInfo.format = GL_LUMINANCE; formatInfo.type = GL_UNSIGNED_BYTE; + formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM; break; default: ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType()); @@ -172,29 +360,37 @@ static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& sourc } } -class ScopedUploadRequest { -public: - ScopedUploadRequest() { beginUpload(); } - ~ScopedUploadRequest() { endUpload(); } -}; + +static void createUploader(bool usingGL) { + static std::mutex lock; + std::lock_guard _lock{lock}; + if (!sUploader.get()) { + if (usingGL) { + sUploader = new EGLUploader(); + } else { + sUploader = new VkUploader(); + } + } +} sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) { ATRACE_CALL(); - FormatInfo format = determineFormat(sourceBitmap); + bool usingGL = uirenderer::Properties::getRenderPipelineType() == + uirenderer::RenderPipelineType::SkiaGL; + + FormatInfo format = determineFormat(sourceBitmap, usingGL); if (!format.valid) { return nullptr; } - ScopedUploadRequest _uploadRequest{}; - SkBitmap bitmap = makeHwCompatible(format, sourceBitmap); sp<GraphicBuffer> buffer = new GraphicBuffer( static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()), format.pixelFormat, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | GraphicBuffer::USAGE_SW_READ_NEVER, - std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + + std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]"); status_t error = buffer->initCheck(); @@ -203,64 +399,24 @@ sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou return nullptr; } - EGLDisplay display = getUploadEglDisplay(); - - LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", - uirenderer::renderthread::EglManager::eglErrorString()); - // We use an EGLImage to access the content of the GraphicBuffer - // The EGL image is later bound to a 2D texture - EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer(); - AutoEglImage autoImage(display, clientBuffer); - if (autoImage.image == EGL_NO_IMAGE_KHR) { - ALOGW("Could not create EGL image, err =%s", - uirenderer::renderthread::EglManager::eglErrorString()); - return nullptr; - } - - { - ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); - EGLSyncKHR fence = sUploadThread->queue().runSync([&]() -> EGLSyncKHR { - AutoSkiaGlTexture glTexture; - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); - GL_CHECKPOINT(MODERATE); - - // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we - // provide. - // But asynchronous in sense that driver may upload texture onto hardware buffer when we - // first - // use it in drawing - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format, - format.type, bitmap.getPixels()); - GL_CHECKPOINT(MODERATE); - - EGLSyncKHR uploadFence = - eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); - LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x", - eglGetError()); - glFlush(); - return uploadFence; - }); - - EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT); - LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, - "Failed to wait for the fence %#x", eglGetError()); + createUploader(usingGL); - eglDestroySyncKHR(display, fence); + if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) { + return nullptr; } - - return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(), + return Bitmap::createFrom(buffer, bitmap.colorType(), bitmap.refColorSpace(), bitmap.alphaType(), Bitmap::computePalette(bitmap)); } +void HardwareBitmapUploader::initialize() { + bool usingGL = uirenderer::Properties::getRenderPipelineType() == + uirenderer::RenderPipelineType::SkiaGL; + createUploader(usingGL); + sUploader->initialize(); +} + void HardwareBitmapUploader::terminate() { - std::lock_guard _lock{sLock}; - LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress"); - if (sUploadThread) { - sUploadThread->requestExit(); - sUploadThread->join(); - sUploadThread = nullptr; - } - sEglManager.destroy(); + sUploader->destroy(); } } // namespace android::uirenderer diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h index 6f41e6db4e32..c300593d47a1 100644 --- a/libs/hwui/HardwareBitmapUploader.h +++ b/libs/hwui/HardwareBitmapUploader.h @@ -22,9 +22,11 @@ namespace android::uirenderer { class ANDROID_API HardwareBitmapUploader { public: - static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap); + static void initialize(); static void terminate(); + static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap); + static bool hasFP16Support(); }; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index def805adeeea..6cce31943d03 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -29,6 +29,7 @@ #include "utils/FatVector.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" +#include "../HardwareBitmapUploader.h" #ifdef HWUI_GLES_WRAP_ENABLED #include "debug/GlesDriver.h" @@ -415,6 +416,7 @@ void RenderThread::preload() { if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { requireVkContext(); } + HardwareBitmapUploader::initialize(); } } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 9298be65c5e8..5f43b488bcf2 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -41,6 +41,7 @@ namespace android { class Bitmap; +class AutoBackendTextureRelease; namespace uirenderer { @@ -135,6 +136,7 @@ private: friend class DispatchFrameCallbacks; friend class RenderProxy; friend class DummyVsyncSource; + friend class android::AutoBackendTextureRelease; friend class android::uirenderer::TestUtils; friend class android::uirenderer::WebViewFunctor; friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler; diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp index 077a8f73b0da..65d95ad36a6f 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.cpp +++ b/libs/hwui/surfacetexture/ImageConsumer.cpp @@ -24,13 +24,17 @@ #include "renderthread/VulkanManager.h" #include "utils/Color.h" #include <GrAHardwareBufferUtils.h> +#include <GrBackendSurface.h> // Macro for including the SurfaceTexture name in log messages #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) +using namespace android::uirenderer::renderthread; + namespace android { void ImageConsumer::onFreeBufferLocked(int slotIndex) { + // This callback may be invoked on any thread. mImageSlots[slotIndex].clear(); } @@ -46,55 +50,141 @@ void ImageConsumer::onReleaseBufferLocked(int buf) { mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR; } +/** + * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object + * that keeps GPU resources alive until the last SKImage object using them is destroyed. + */ +class AutoBackendTextureRelease { +public: + static void releaseProc(SkImage::ReleaseContext releaseContext); + + AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer); + + const GrBackendTexture& getTexture() const { return mBackendTexture; } + + void ref() { mUsageCount++; } + + void unref(bool releaseImage); + + inline sk_sp<SkImage> getImage() { return mImage; } + + void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace, + GrContext* context); + +private: + // The only way to invoke dtor is with unref, when mUsageCount is 0. + ~AutoBackendTextureRelease() {} + + GrBackendTexture mBackendTexture; + GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; + GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx; + + // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs + // are held by SkImages. + int mUsageCount = 1; + + // mImage is the SkImage created from mBackendTexture. + sk_sp<SkImage> mImage; +}; + +AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer) { + bool createProtectedImage = + 0 != (buffer->getUsage() & GraphicBuffer::USAGE_PROTECTED); + GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat( + context, + reinterpret_cast<AHardwareBuffer*>(buffer), + buffer->getPixelFormat(), + false); + mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture( + context, + reinterpret_cast<AHardwareBuffer*>(buffer), + buffer->getWidth(), + buffer->getHeight(), + &mDeleteProc, + &mDeleteCtx, + createProtectedImage, + backendFormat, + false); +} + +void AutoBackendTextureRelease::unref(bool releaseImage) { + if (!RenderThread::isCurrent()) { + // EGLImage needs to be destroyed on RenderThread to prevent memory leak. + // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not + // thread safe. + RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); }); + return; + } + + if (releaseImage) { + mImage.reset(); + } + + mUsageCount--; + if (mUsageCount <= 0) { + if (mBackendTexture.isValid()) { + mDeleteProc(mDeleteCtx); + mBackendTexture = {}; + } + delete this; + } +} + +void AutoBackendTextureRelease::releaseProc(SkImage::ReleaseContext releaseContext) { + AutoBackendTextureRelease* textureRelease = + reinterpret_cast<AutoBackendTextureRelease*>(releaseContext); + textureRelease->unref(false); +} + +void AutoBackendTextureRelease::makeImage(sp<GraphicBuffer>& graphicBuffer, + android_dataspace dataspace, GrContext* context) { + SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat( + graphicBuffer->getPixelFormat()); + mImage = SkImage::MakeFromTexture(context, + mBackendTexture, + kTopLeft_GrSurfaceOrigin, + colorType, + kPremul_SkAlphaType, + uirenderer::DataSpaceToColorSpace(dataspace), + releaseProc, + this); + if (mImage.get()) { + // The following ref will be counteracted by releaseProc, when SkImage is discarded. + ref(); + } +} + void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace, bool forceCreate, GrContext* context) { - if (!mImage.get() || dataspace != mDataspace || forceCreate) { + if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace + || forceCreate) { if (!graphicBuffer.get()) { clear(); return; } - if (!mBackendTexture.isValid()) { - clear(); - bool createProtectedImage = - 0 != (graphicBuffer->getUsage() & GraphicBuffer::USAGE_PROTECTED); - GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat( - context, - reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), - graphicBuffer->getPixelFormat(), - false); - mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture( - context, - reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), - graphicBuffer->getWidth(), - graphicBuffer->getHeight(), - &mDeleteProc, - &mDeleteCtx, - createProtectedImage, - backendFormat, - false); + if (!mTextureRelease) { + mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get()); } + mDataspace = dataspace; - SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat( - graphicBuffer->getPixelFormat()); - mImage = SkImage::MakeFromTexture(context, - mBackendTexture, - kTopLeft_GrSurfaceOrigin, - colorType, - kPremul_SkAlphaType, - uirenderer::DataSpaceToColorSpace(dataspace)); + mTextureRelease->makeImage(graphicBuffer, dataspace, context); } } void ImageConsumer::ImageSlot::clear() { - mImage.reset(); - if (mBackendTexture.isValid()) { - mDeleteProc(mDeleteCtx); - mBackendTexture = {}; + if (mTextureRelease) { + // The following unref counteracts the initial mUsageCount of 1, set by default initializer. + mTextureRelease->unref(true); + mTextureRelease = nullptr; } } +sk_sp<SkImage> ImageConsumer::ImageSlot::getImage() { + return mTextureRelease ? mTextureRelease->getImage() : nullptr; +} + sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, uirenderer::RenderState& renderState) { BufferItem item; diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h index eee0a0ac3512..2fdece989876 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -25,7 +25,6 @@ #include <cutils/compiler.h> #include <gui/BufferItem.h> #include <system/graphics.h> -#include <GrBackendSurface.h> namespace GrAHardwareBufferUtils { typedef void* DeleteImageCtx; @@ -38,6 +37,7 @@ namespace uirenderer { class RenderState; } +class AutoBackendTextureRelease; class SurfaceTexture; /* @@ -81,16 +81,14 @@ private: void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace, bool forceCreate, GrContext* context); + void clear(); inline EGLSyncKHR& eglFence() { return mEglFence; } - inline sk_sp<SkImage> getImage() { return mImage; } + sk_sp<SkImage> getImage(); private: - // mImage is the SkImage created from mGraphicBuffer. - sk_sp<SkImage> mImage; - // the dataspace associated with the current image android_dataspace mDataspace; @@ -100,11 +98,11 @@ private: */ EGLSyncKHR mEglFence; - GrBackendTexture mBackendTexture; - - GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; - - GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx; + /** + * mTextureRelease may outlive ImageConsumer, if the last ref is held by an SkImage. + * ImageConsumer holds one ref to mTextureRelease, which is decremented by "clear". + */ + AutoBackendTextureRelease* mTextureRelease = nullptr; }; /** diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 050b2ec26c8d..01f17986d88c 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -167,9 +167,9 @@ public class LocationManager { /** * Broadcast intent action when the set of enabled location providers changes. To check the - * status of a provider, use {@link #isProviderEnabled(String)}. Depending on API level, may + * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider - * whose state has changed. See {@link #EXTRA_PROVIDER_NAME} for the supported API level. + * whose state has changed. * * @see #EXTRA_PROVIDER_NAME */ diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java index 5cd36216929e..fbe184bf144f 100644 --- a/media/apex/java/android/media/MediaPlayer2.java +++ b/media/apex/java/android/media/MediaPlayer2.java @@ -3463,7 +3463,7 @@ public class MediaPlayer2 implements AutoCloseable * @param uuid of selected crypto scheme * @return this */ - public Builder setUuid(@NonNull UUID uuid) { + public @NonNull Builder setUuid(@NonNull UUID uuid) { this.mUUID = uuid; return this; } @@ -3480,7 +3480,7 @@ public class MediaPlayer2 implements AutoCloseable * @param keySetId identifier of a persisted offline key * @return this */ - public Builder setKeySetId(@Nullable byte[] keySetId) { + public @NonNull Builder setKeySetId(@Nullable byte[] keySetId) { this.mKeySetId = keySetId; return this; } @@ -3494,7 +3494,7 @@ public class MediaPlayer2 implements AutoCloseable * @param initData container-specific DRM initialization data * @return this */ - public Builder setInitData(@Nullable byte[] initData) { + public @NonNull Builder setInitData(@Nullable byte[] initData) { this.mInitData = initData; return this; } @@ -3505,7 +3505,7 @@ public class MediaPlayer2 implements AutoCloseable * @param mimeType mime type to the content * @return this */ - public Builder setMimeType(@Nullable String mimeType) { + public @NonNull Builder setMimeType(@Nullable String mimeType) { this.mMimeType = mimeType; return this; } @@ -3519,7 +3519,7 @@ public class MediaPlayer2 implements AutoCloseable * @param keyType type of the key request * @return this */ - public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) { + public @NonNull Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) { this.mKeyType = keyType; return this; } @@ -3531,7 +3531,8 @@ public class MediaPlayer2 implements AutoCloseable * @param optionalParameters optional parameters to be included in a key request * @return this */ - public Builder setOptionalParameters(@Nullable Map<String, String> optionalParameters) { + public @NonNull Builder setOptionalParameters( + @Nullable Map<String, String> optionalParameters) { this.mOptionalParameters = optionalParameters; return this; } @@ -3540,7 +3541,7 @@ public class MediaPlayer2 implements AutoCloseable * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the * settings of this builder */ - public MediaPlayer2.DrmPreparationInfo build() { + public @NonNull MediaPlayer2.DrmPreparationInfo build() { return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType, mKeyType, mOptionalParameters); } @@ -3597,7 +3598,8 @@ public class MediaPlayer2 implements AutoCloseable * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip * DRM initialization */ - public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { + public @Nullable DrmPreparationInfo onDrmInfo(@NonNull MediaPlayer2 mp, + @NonNull DataSourceDesc dsd, @NonNull DrmInfo drmInfo) { return null; } @@ -3630,11 +3632,13 @@ public class MediaPlayer2 implements AutoCloseable * @param request a {@link MediaDrm.KeyRequest} prepared using the * {@link DrmPreparationInfo} returned from * {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)} - * @return the response to {@code request} (from license server) + * @return the response to {@code request} (from license server); returning {@code null} or + * throwing an {@link RuntimeException} from this callback would trigger an + * {@link EventCallback#onError}. */ - public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, - @NonNull MediaDrm.KeyRequest request) { - return null; + public @NonNull byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, + @NonNull DataSourceDesc dsd, @NonNull MediaDrm.KeyRequest request) { + return new byte[0]; } /** @@ -4144,7 +4148,7 @@ public class MediaPlayer2 implements AutoCloseable /** * Returns the PSSH info of the data source for each supported DRM scheme. */ - public Map<UUID, byte[]> getPssh() { + public @NonNull Map<UUID, byte[]> getPssh() { return mMapPssh; } @@ -4153,7 +4157,7 @@ public class MediaPlayer2 implements AutoCloseable * It effectively identifies the subset of the source's DRM schemes which * are supported by the device too. */ - public List<UUID> getSupportedSchemes() { + public @NonNull List<UUID> getSupportedSchemes() { return Arrays.asList(mSupportedSchemes); } @@ -4276,7 +4280,7 @@ public class MediaPlayer2 implements AutoCloseable * Extends MediaDrm.MediaDrmException */ public static final class NoDrmSchemeException extends MediaDrmException { - public NoDrmSchemeException(String detailMessage) { + public NoDrmSchemeException(@Nullable String detailMessage) { super(detailMessage); } } diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java index 20d6391526dd..6822ea56b5e8 100644 --- a/media/apex/java/android/media/Session2Command.java +++ b/media/apex/java/android/media/Session2Command.java @@ -32,6 +32,10 @@ import java.util.Objects; * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and * {@link #getCustomCommand()} shouldn't be {@code null}. * <p> + * Refer to the + * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a> + * class for the list of valid commands. + * <p> * This API is not generally intended for third party application developers. * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a> diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 6a595d27d592..f9080a70206e 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1820,6 +1820,21 @@ public class AudioManager { "android.media.action.MICROPHONE_MUTE_CHANGED"; /** + * Broadcast Action: speakerphone state changed. + * + * You <em>cannot</em> receive this through components declared + * in manifests, only by explicitly registering for it with + * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) + * Context.registerReceiver()}. + * + * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the + * speakerphone functionality is enabled or not. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = + "android.media.action.SPEAKERPHONE_STATE_CHANGED"; + + /** * Sets the audio mode. * <p> * The audio mode encompasses audio routing AND the behavior of diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 12e02e7b73cd..27499c6160d3 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -1036,6 +1036,15 @@ public final class MediaFormat { */ public static final String KEY_CA_PRIVATE_DATA = "ca-private-data"; + /** + * A key describing the maximum number of B frames between I or P frames, + * to be used by a video encoder. + * The associated value is an integer. The default value is 0, which means + * that no B frames are allowed. Note that non-zero value does not guarantee + * B frames; it's up to the encoder to decide. + */ + public static final String KEY_MAX_BFRAMES = "max-bframes"; + /* package private */ MediaFormat(@NonNull Map<String, Object> map) { mMap = map; } diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java index d72476269e18..3838a99969f0 100644 --- a/media/java/android/media/MediaHTTPConnection.java +++ b/media/java/android/media/MediaHTTPConnection.java @@ -37,6 +37,7 @@ import java.net.URL; import java.net.UnknownServiceException; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; /** @hide */ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @@ -46,27 +47,23 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // connection timeout - 30 sec private static final int CONNECT_TIMEOUT_MS = 30 * 1000; - @UnsupportedAppUsage - private long mCurrentOffset = -1; - @UnsupportedAppUsage - private URL mURL = null; - @UnsupportedAppUsage - private Map<String, String> mHeaders = null; - @UnsupportedAppUsage - private HttpURLConnection mConnection = null; - @UnsupportedAppUsage - private long mTotalSize = -1; - private InputStream mInputStream = null; - - @UnsupportedAppUsage - private boolean mAllowCrossDomainRedirect = true; - @UnsupportedAppUsage - private boolean mAllowCrossProtocolRedirect = true; - // from com.squareup.okhttp.internal.http private final static int HTTP_TEMP_REDIRECT = 307; private final static int MAX_REDIRECTS = 20; + class ConnectionState { + public HttpURLConnection mConnection = null; + public InputStream mInputStream = null; + public long mCurrentOffset = -1; + public Map<String, String> mHeaders = null; + public URL mURL = null; + public long mTotalSize = -1; + public boolean mAllowCrossDomainRedirect = true; + public boolean mAllowCrossProtocolRedirect = true; + } + private final AtomicReference<ConnectionState> mConnectionStateHolder = + new AtomicReference<ConnectionState>(); + @UnsupportedAppUsage public MediaHTTPConnection() { CookieHandler cookieHandler = CookieHandler.getDefault(); @@ -84,13 +81,23 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers); } + ConnectionState connectionState = mConnectionStateHolder.get(); + synchronized (this) { + if (connectionState == null) { + connectionState = new ConnectionState(); + mConnectionStateHolder.set(connectionState); + } + } + try { disconnect(); - mAllowCrossDomainRedirect = true; - mURL = new URL(uri); - mHeaders = convertHeaderStringToMap(headers); + connectionState.mAllowCrossDomainRedirect = true; + connectionState.mURL = new URL(uri); + connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState); } catch (MalformedURLException e) { return null; + } finally { + mConnectionStateHolder.set(connectionState); } return native_getIMemory(); @@ -106,18 +113,21 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } /* returns true iff header is internal */ - private boolean filterOutInternalHeaders(String key, String val) { + private boolean filterOutInternalHeaders( + String key, String val, ConnectionState connectionState) { if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) { - mAllowCrossDomainRedirect = parseBoolean(val); + connectionState.mAllowCrossDomainRedirect = parseBoolean(val); // cross-protocol redirects are also controlled by this flag - mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect; + connectionState.mAllowCrossProtocolRedirect = + connectionState.mAllowCrossDomainRedirect; } else { return false; } return true; } - private Map<String, String> convertHeaderStringToMap(String headers) { + private Map<String, String> convertHeaderStringToMap(String headers, + ConnectionState connectionState) { HashMap<String, String> map = new HashMap<String, String>(); String[] pairs = headers.split("\r\n"); @@ -127,7 +137,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { String key = pair.substring(0, colonPos); String val = pair.substring(colonPos + 1); - if (!filterOutInternalHeaders(key, val)) { + if (!filterOutInternalHeaders(key, val, connectionState)) { map.put(key, val); } } @@ -139,25 +149,28 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public void disconnect() { - teardownConnection(); - mHeaders = null; - mURL = null; + ConnectionState connectionState = mConnectionStateHolder.getAndSet(null); + if (connectionState != null) { + teardownConnection(connectionState); + connectionState.mHeaders = null; + connectionState.mURL = null; + } } - private void teardownConnection() { - if (mConnection != null) { - if (mInputStream != null) { + private void teardownConnection(ConnectionState connectionState) { + if (connectionState.mConnection != null) { + if (connectionState.mInputStream != null) { try { - mInputStream.close(); + connectionState.mInputStream.close(); } catch (IOException e) { } - mInputStream = null; + connectionState.mInputStream = null; } - mConnection.disconnect(); - mConnection = null; + connectionState.mConnection.disconnect(); + connectionState.mConnection = null; - mCurrentOffset = -1; + connectionState.mCurrentOffset = -1; } } @@ -184,42 +197,44 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { return false; } - private void seekTo(long offset) throws IOException { - teardownConnection(); + private void seekTo(long offset, ConnectionState connectionState) throws IOException { + teardownConnection(connectionState); try { int response; int redirectCount = 0; - URL url = mURL; + URL url = connectionState.mURL; // do not use any proxy for localhost (127.0.0.1) boolean noProxy = isLocalHost(url); while (true) { if (noProxy) { - mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); + connectionState.mConnection = + (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); } else { - mConnection = (HttpURLConnection)url.openConnection(); + connectionState.mConnection = (HttpURLConnection) url.openConnection(); } - mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); + connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); // handle redirects ourselves if we do not allow cross-domain redirect - mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect); + connectionState.mConnection.setInstanceFollowRedirects( + connectionState.mAllowCrossDomainRedirect); - if (mHeaders != null) { - for (Map.Entry<String, String> entry : mHeaders.entrySet()) { - mConnection.setRequestProperty( + if (connectionState.mHeaders != null) { + for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) { + connectionState.mConnection.setRequestProperty( entry.getKey(), entry.getValue()); } } if (offset > 0) { - mConnection.setRequestProperty( + connectionState.mConnection.setRequestProperty( "Range", "bytes=" + offset + "-"); } - response = mConnection.getResponseCode(); + response = connectionState.mConnection.getResponseCode(); if (response != HttpURLConnection.HTTP_MULT_CHOICE && response != HttpURLConnection.HTTP_MOVED_PERM && response != HttpURLConnection.HTTP_MOVED_TEMP && @@ -233,7 +248,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new NoRouteToHostException("Too many redirects: " + redirectCount); } - String method = mConnection.getRequestMethod(); + String method = connectionState.mConnection.getRequestMethod(); if (response == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { // "If the 307 status code is received in response to a @@ -241,34 +256,35 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // automatically redirect the request" throw new NoRouteToHostException("Invalid redirect"); } - String location = mConnection.getHeaderField("Location"); + String location = connectionState.mConnection.getHeaderField("Location"); if (location == null) { throw new NoRouteToHostException("Invalid redirect"); } - url = new URL(mURL /* TRICKY: don't use url! */, location); + url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location); if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) { throw new NoRouteToHostException("Unsupported protocol redirect"); } - boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol()); - if (!mAllowCrossProtocolRedirect && !sameProtocol) { + boolean sameProtocol = + connectionState.mURL.getProtocol().equals(url.getProtocol()); + if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) { throw new NoRouteToHostException("Cross-protocol redirects are disallowed"); } - boolean sameHost = mURL.getHost().equals(url.getHost()); - if (!mAllowCrossDomainRedirect && !sameHost) { + boolean sameHost = connectionState.mURL.getHost().equals(url.getHost()); + if (!connectionState.mAllowCrossDomainRedirect && !sameHost) { throw new NoRouteToHostException("Cross-domain redirects are disallowed"); } if (response != HTTP_TEMP_REDIRECT) { // update effective URL, unless it is a Temporary Redirect - mURL = url; + connectionState.mURL = url; } } - if (mAllowCrossDomainRedirect) { + if (connectionState.mAllowCrossDomainRedirect) { // remember the current, potentially redirected URL if redirects // were handled by HttpURLConnection - mURL = mConnection.getURL(); + connectionState.mURL = connectionState.mConnection.getURL(); } if (response == HttpURLConnection.HTTP_PARTIAL) { @@ -276,10 +292,9 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // because what we want is not just the length of the range // returned but the size of the full content if available. - String contentRange = - mConnection.getHeaderField("Content-Range"); + String contentRange = connectionState.mConnection.getHeaderField("Content-Range"); - mTotalSize = -1; + connectionState.mTotalSize = -1; if (contentRange != null) { // format is "bytes xxx-yyy/zzz // where "zzz" is the total number of bytes of the @@ -291,7 +306,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { contentRange.substring(lastSlashPos + 1); try { - mTotalSize = Long.parseLong(total); + connectionState.mTotalSize = Long.parseLong(total); } catch (NumberFormatException e) { } } @@ -299,7 +314,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } else if (response != HttpURLConnection.HTTP_OK) { throw new IOException(); } else { - mTotalSize = mConnection.getContentLength(); + connectionState.mTotalSize = connectionState.mConnection.getContentLength(); } if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) { @@ -308,14 +323,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new ProtocolException(); } - mInputStream = - new BufferedInputStream(mConnection.getInputStream()); + connectionState.mInputStream = + new BufferedInputStream(connectionState.mConnection.getInputStream()); - mCurrentOffset = offset; + connectionState.mCurrentOffset = offset; } catch (IOException e) { - mTotalSize = -1; - teardownConnection(); - mCurrentOffset = -1; + connectionState.mTotalSize = -1; + teardownConnection(connectionState); + connectionState.mCurrentOffset = -1; throw e; } @@ -324,10 +339,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public int readAt(long offset, int size) { - return native_readAt(offset, size); + ConnectionState connectionState = mConnectionStateHolder.get(); + if (connectionState != null) { + return native_readAt(offset, size, connectionState); + } + return -1; } - private int readAt(long offset, byte[] data, int size) { + private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); @@ -335,12 +354,12 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { try { synchronized(this) { - if (offset != mCurrentOffset) { - seekTo(offset); + if (offset != connectionState.mCurrentOffset) { + seekTo(offset, connectionState); } } - int n = mInputStream.read(data, 0, size); + int n = connectionState.mInputStream.read(data, 0, size); if (n == -1) { // InputStream signals EOS using a -1 result, our semantics @@ -348,7 +367,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { n = 0; } - mCurrentOffset += n; + connectionState.mCurrentOffset += n; if (VERBOSE) { Log.d(TAG, "readAt " + offset + " / " + size + " => " + n); @@ -380,35 +399,47 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override public synchronized long getSize() { - if (mConnection == null) { - try { - seekTo(0); - } catch (IOException e) { - return -1; + ConnectionState connectionState = mConnectionStateHolder.get(); + if (connectionState != null) { + if (connectionState.mConnection == null) { + try { + seekTo(0, connectionState); + } catch (IOException e) { + return -1; + } } + return connectionState.mTotalSize; } - return mTotalSize; + return -1; } @Override @UnsupportedAppUsage public synchronized String getMIMEType() { - if (mConnection == null) { - try { - seekTo(0); - } catch (IOException e) { - return "application/octet-stream"; + ConnectionState connectionState = mConnectionStateHolder.get(); + if (connectionState != null) { + if (connectionState.mConnection == null) { + try { + seekTo(0, connectionState); + } catch (IOException e) { + return "application/octet-stream"; + } } + return connectionState.mConnection.getContentType(); } - return mConnection.getContentType(); + return null; } @Override @UnsupportedAppUsage public String getUri() { - return mURL.toString(); + ConnectionState connectionState = mConnectionStateHolder.get(); + if (connectionState != null) { + return connectionState.mURL.toString(); + } + return null; } @Override @@ -421,7 +452,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { private native final void native_finalize(); private native final IBinder native_getIMemory(); - private native final int native_readAt(long offset, int size); + private native int native_readAt(long offset, int size, ConnectionState connectionState); static { System.loadLibrary("media_jni"); diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl index cfcc2946bbdb..023484764a52 100644 --- a/media/java/android/media/session/ISessionManager.aidl +++ b/media/java/android/media/session/ISessionManager.aidl @@ -22,10 +22,10 @@ import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyListener; import android.media.session.IOnVolumeKeyLongPressListener; +import android.media.session.ISession; import android.media.session.ISession2TokensListener; import android.media.session.MediaSession; import android.media.session.SessionCallbackLink; -import android.media.session.SessionLink; import android.os.Bundle; import android.view.KeyEvent; @@ -34,7 +34,7 @@ import android.view.KeyEvent; * @hide */ interface ISessionManager { - SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag, + ISession createSession(String packageName, in SessionCallbackLink sessionCb, String tag, in Bundle sessionInfo, int userId); void notifySession2Created(in Session2Token sessionToken); List<MediaSession.Token> getSessions(in ComponentName compName, int userId); diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 4fc436c7ed31..cbc6c9d6e451 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -36,6 +36,7 @@ import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; +import android.os.RemoteException; import android.os.ResultReceiver; import android.service.media.MediaBrowserService; import android.text.TextUtils; @@ -163,11 +164,11 @@ public final class MediaSession { .getSystemService(Context.MEDIA_SESSION_SERVICE); try { SessionCallbackLink cbLink = new SessionCallbackLink(context); - SessionLink sessionLink = manager.createSession(cbLink, tag, sessionInfo); - mImpl = new MediaSessionEngine(context, sessionLink, cbLink); + ISession binder = manager.createSession(cbLink, tag, sessionInfo); + mImpl = new MediaSessionEngine(context, binder, cbLink); mMaxBitmapSize = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize); - } catch (RuntimeException e) { + } catch (RemoteException e) { throw new RuntimeException("Remote error creating session.", e); } } diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java index 266bf3226c49..7c5243ac31cd 100644 --- a/media/java/android/media/session/MediaSessionEngine.java +++ b/media/java/android/media/session/MediaSessionEngine.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.media.AudioAttributes; import android.media.MediaDescription; import android.media.MediaMetadata; +import android.media.MediaParceledListSlice; import android.media.Rating; import android.media.VolumeProvider; import android.media.session.MediaSessionManager.RemoteUserInfo; @@ -34,6 +35,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Parcel; +import android.os.RemoteException; import android.os.ResultReceiver; import android.service.media.MediaBrowserService; import android.text.TextUtils; @@ -55,7 +57,7 @@ public final class MediaSessionEngine implements AutoCloseable { private final MediaSession.Token mSessionToken; private final MediaController mController; - private final SessionLink mSessionLink; + private final ISession mBinder; private CallbackMessageHandler mCallbackHandler; private VolumeProvider mVolumeProvider; @@ -70,14 +72,14 @@ public final class MediaSessionEngine implements AutoCloseable { * finished with the session. * * @param context The context to use to create the session. - * @param sessionLink A session link for the binder of MediaSessionRecord + * @param binder A session binder */ - public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink, - @NonNull SessionCallbackLink cbLink) { - mSessionLink = sessionLink; + public MediaSessionEngine(@NonNull Context context, @NonNull ISession binder, + @NonNull SessionCallbackLink cbLink) throws RemoteException { + mBinder = binder; cbLink.setSessionEngine(this); - mSessionToken = new MediaSession.Token(mSessionLink.getController()); + mSessionToken = new MediaSession.Token(mBinder.getController()); mController = new MediaController(context, mSessionToken); } @@ -134,8 +136,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void setSessionActivity(@Nullable PendingIntent pi) { try { - mSessionLink.setLaunchPendingIntent(pi); - } catch (RuntimeException e) { + mBinder.setLaunchPendingIntent(pi); + } catch (RemoteException e) { Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e); } } @@ -150,8 +152,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { try { - mSessionLink.setMediaButtonReceiver(mbr); - } catch (RuntimeException e) { + mBinder.setMediaButtonReceiver(mbr); + } catch (RemoteException e) { Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e); } } @@ -163,8 +165,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void setFlags(int flags) { try { - mSessionLink.setFlags(flags); - } catch (RuntimeException e) { + mBinder.setFlags(flags); + } catch (RemoteException e) { Log.wtf(TAG, "Failure in setFlags.", e); } } @@ -185,8 +187,8 @@ public final class MediaSessionEngine implements AutoCloseable { throw new IllegalArgumentException("Attributes cannot be null for local playback."); } try { - mSessionLink.setPlaybackToLocal(attributes); - } catch (RuntimeException e) { + mBinder.setPlaybackToLocal(attributes); + } catch (RemoteException e) { Log.wtf(TAG, "Failure in setPlaybackToLocal.", e); } } @@ -217,10 +219,10 @@ public final class MediaSessionEngine implements AutoCloseable { }); try { - mSessionLink.setPlaybackToRemote(volumeProvider.getVolumeControl(), + mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(), volumeProvider.getMaxVolume()); - mSessionLink.setCurrentVolume(volumeProvider.getCurrentVolume()); - } catch (RuntimeException e) { + mBinder.setCurrentVolume(volumeProvider.getCurrentVolume()); + } catch (RemoteException e) { Log.wtf(TAG, "Failure in setPlaybackToRemote.", e); } } @@ -238,9 +240,9 @@ public final class MediaSessionEngine implements AutoCloseable { return; } try { - mSessionLink.setActive(active); + mBinder.setActive(active); mActive = active; - } catch (RuntimeException e) { + } catch (RemoteException e) { Log.wtf(TAG, "Failure in setActive.", e); } } @@ -267,8 +269,8 @@ public final class MediaSessionEngine implements AutoCloseable { throw new IllegalArgumentException("event cannot be null or empty"); } try { - mSessionLink.sendEvent(event, extras); - } catch (RuntimeException e) { + mBinder.sendEvent(event, extras); + } catch (RemoteException e) { Log.wtf(TAG, "Error sending event", e); } } @@ -280,8 +282,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void close() { try { - mSessionLink.destroySession(); - } catch (RuntimeException e) { + mBinder.destroySession(); + } catch (RemoteException e) { Log.wtf(TAG, "Error releasing session: ", e); } } @@ -316,8 +318,8 @@ public final class MediaSessionEngine implements AutoCloseable { public void setPlaybackState(@Nullable PlaybackState state) { mPlaybackState = state; try { - mSessionLink.setPlaybackState(state); - } catch (RuntimeException e) { + mBinder.setPlaybackState(state); + } catch (RemoteException e) { Log.wtf(TAG, "Dead object in setPlaybackState.", e); } } @@ -344,8 +346,8 @@ public final class MediaSessionEngine implements AutoCloseable { String metadataDescription = "size=" + fields + ", description=" + description; try { - mSessionLink.setMetadata(metadata, duration, metadataDescription); - } catch (RuntimeException e) { + mBinder.setMetadata(metadata, duration, metadataDescription); + } catch (RemoteException e) { Log.wtf(TAG, "Dead object in setPlaybackState.", e); } } @@ -363,8 +365,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void setQueue(@Nullable List<MediaSession.QueueItem> queue) { try { - mSessionLink.setQueue(queue); - } catch (RuntimeException e) { + mBinder.setQueue(queue == null ? null : new MediaParceledListSlice(queue)); + } catch (RemoteException e) { Log.wtf("Dead object in setQueue.", e); } } @@ -378,8 +380,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void setQueueTitle(@Nullable CharSequence title) { try { - mSessionLink.setQueueTitle(title); - } catch (RuntimeException e) { + mBinder.setQueueTitle(title); + } catch (RemoteException e) { Log.wtf("Dead object in setQueueTitle.", e); } } @@ -399,8 +401,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void setRatingType(int type) { try { - mSessionLink.setRatingType(type); - } catch (RuntimeException e) { + mBinder.setRatingType(type); + } catch (RemoteException e) { Log.e(TAG, "Error in setRatingType.", e); } } @@ -414,8 +416,8 @@ public final class MediaSessionEngine implements AutoCloseable { */ public void setExtras(@Nullable Bundle extras) { try { - mSessionLink.setExtras(extras); - } catch (RuntimeException e) { + mBinder.setExtras(extras); + } catch (RemoteException e) { Log.wtf("Dead object in setExtras.", e); } } @@ -464,8 +466,8 @@ public final class MediaSessionEngine implements AutoCloseable { } } try { - mSessionLink.setCurrentVolume(provider.getCurrentVolume()); - } catch (RuntimeException e) { + mBinder.setCurrentVolume(provider.getCurrentVolume()); + } catch (RemoteException e) { Log.e(TAG, "Error in notifyVolumeChanged", e); } } diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index f530442bf087..7ca5c9398394 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -107,7 +107,7 @@ public final class MediaSessionManager { * @hide */ @NonNull - public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag, + public ISession createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag, @Nullable Bundle sessionInfo) { try { return mService.createSession(mContext.getPackageName(), cbStub, tag, sessionInfo, diff --git a/media/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java deleted file mode 100644 index a47c26214f25..000000000000 --- a/media/java/android/media/session/SessionLink.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright 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 android.media.session; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.PendingIntent; -import android.media.AudioAttributes; -import android.media.MediaMetadata; -import android.media.MediaParceledListSlice; -import android.media.session.MediaSession.QueueItem; -import android.os.Bundle; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.RemoteException; - -import java.util.List; - -/** - * Handles incoming commands from {@link MediaSession}. - * @hide - */ -public final class SessionLink implements Parcelable { - public static final @android.annotation.NonNull Parcelable.Creator<SessionLink> CREATOR = - new Parcelable.Creator<SessionLink>() { - @Override - public SessionLink createFromParcel(Parcel in) { - return new SessionLink(in.readStrongBinder()); - } - - @Override - public SessionLink[] newArray(int size) { - return new SessionLink[size]; - } - }; - - final SessionStub mSessionStub; - final ISession mISession; - - /** - * Constructor for stub (Callee) - */ - public SessionLink(@NonNull SessionStub sessionStub) { - mSessionStub = sessionStub; - mISession = new StubProxy(); - } - - /** - * Constructor for interface (Caller) - */ - public SessionLink(IBinder binder) { - mSessionStub = null; - mISession = ISession.Stub.asInterface(binder); - } - - /** - * Tell system that the session sends an event to all the connected controllers. - * - * @param event the name of the event - * @param extras the extras included with the event - */ - void sendEvent(@NonNull String event, @Nullable Bundle extras) { - try { - mISession.sendEvent(event, extras); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Gets the controller binder from the system. - */ - @NonNull - ISessionController getController() { - try { - return mISession.getController(); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the flags. - * - * @param flags the new session flags - */ - void setFlags(int flags) { - try { - mISession.setFlags(flags); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session is (in)active. - * - * @param active the new activeness state - */ - void setActive(boolean active) { - try { - mISession.setActive(active); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the media button receiver. - * - * @param mbr the pending intent for media button receiver - */ - void setMediaButtonReceiver(@Nullable PendingIntent mbr) { - try { - mISession.setMediaButtonReceiver(mbr); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the pending intent for launching UI. - * - * @param pi the pending intent for launching UI - */ - void setLaunchPendingIntent(@Nullable PendingIntent pi) { - try { - mISession.setLaunchPendingIntent(pi); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session is destroyed. - */ - void destroySession() { - try { - mISession.destroySession(); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the new metadata. - * - * @param metadata the new metadata - * @param duration the duration of the media in milliseconds - * @param metadataDescription the description of the metadata - */ - void setMetadata(@Nullable MediaMetadata metadata, long duration, - @Nullable String metadataDescription) { - try { - mISession.setMetadata(metadata, duration, metadataDescription); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the new playback state. - * - * @param state the new playback state - */ - void setPlaybackState(@Nullable PlaybackState state) { - try { - mISession.setPlaybackState(state); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the new queue. - * - * @param queue the new queue - */ - void setQueue(@Nullable List<QueueItem> queue) { - try { - mISession.setQueue(queue == null ? null : new MediaParceledListSlice(queue)); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the new queue title. - * - * @param title the new queue title - */ - void setQueueTitle(@Nullable CharSequence title) { - try { - mISession.setQueueTitle(title); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the new extras. - * - * @param extras the new extras - */ - void setExtras(@Nullable Bundle extras) { - try { - mISession.setExtras(extras); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the new rating type of the current media. - * - * @param type the rating type. - */ - void setRatingType(int type) { - try { - mISession.setRatingType(type); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session represents a local playback. - * - * @param attributes the audio attributes of the local playback. - */ - void setPlaybackToLocal(@NonNull AudioAttributes attributes) { - try { - mISession.setPlaybackToLocal(attributes); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session represents a remote playback. - * - * @param control the volume control type - * @param max the max volume - */ - void setPlaybackToRemote(int control, int max) { - try { - mISession.setPlaybackToRemote(control, max); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tell system that the session sets the new current volume. - * - * @param currentVolume the new current volume - */ - void setCurrentVolume(int currentVolume) { - try { - mISession.setCurrentVolume(currentVolume); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** Gets the binder */ - @NonNull - public IBinder getBinder() { - return mISession.asBinder(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeStrongBinder(mISession.asBinder()); - } - - /** - * Class for Stub implementation - */ - public abstract static class SessionStub { - /** Stub method for ISession.sendEvent */ - public void sendEvent(@NonNull String event, @Nullable Bundle data) { - } - - /** Stub method for ISession.getController */ - @NonNull - public ISessionController getController() { - return null; - } - - /** Stub method for ISession.setFlags */ - public void setFlags(int flags) { - } - - /** Stub method for ISession.setActive */ - public void setActive(boolean active) { - } - - /** Stub method for ISession.setMediaButtonReceiver */ - public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { - } - - /** Stub method for ISession.setLaunchPendingIntent */ - public void setLaunchPendingIntent(@Nullable PendingIntent pi) { - } - - /** Stub method for ISession.destroySession */ - public void destroySession() { - } - - /** Stub method for ISession.setMetadata */ - public void setMetadata(@Nullable MediaMetadata metadata, long duration, - @Nullable String metadataDescription) { - } - - /** Stub method for ISession.setPlaybackState */ - public void setPlaybackState(@Nullable PlaybackState state) { - } - - /** Stub method for ISession.setQueue */ - public void setQueue(@Nullable List<QueueItem> queue) { - } - - /** Stub method for ISession.setQueueTitle */ - public void setQueueTitle(@Nullable CharSequence title) { - } - - /** Stub method for ISession.setExtras */ - public void setExtras(@Nullable Bundle extras) { - } - - /** Stub method for ISession.setRatingType */ - public void setRatingType(int type) { - } - - /** Stub method for ISession.setPlaybackToLocal */ - public void setPlaybackToLocal(@NonNull AudioAttributes attributes) { - } - - /** Stub method for ISession.setPlaybackToRemote */ - public void setPlaybackToRemote(int control, int max) { - } - - /** Stub method for ISession.setCurrentVolume */ - public void setCurrentVolume(int currentVolume) { - } - } - - private class StubProxy extends ISession.Stub { - @Override - public void sendEvent(String event, Bundle data) { - mSessionStub.sendEvent(event, data); - } - - @Override - public ISessionController getController() { - return mSessionStub.getController(); - } - - @Override - public void setFlags(int flags) { - mSessionStub.setFlags(flags); - } - - @Override - public void setActive(boolean active) { - mSessionStub.setActive(active); - } - - @Override - public void setMediaButtonReceiver(PendingIntent mbr) { - mSessionStub.setMediaButtonReceiver(mbr); - } - - @Override - public void setLaunchPendingIntent(PendingIntent pi) { - mSessionStub.setLaunchPendingIntent(pi); - } - - @Override - public void destroySession() { - mSessionStub.destroySession(); - } - - @Override - public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) { - mSessionStub.setMetadata(metadata, duration, metadataDescription); - } - - @Override - public void setPlaybackState(PlaybackState state) { - mSessionStub.setPlaybackState(state); - } - - @Override - public void setQueue(MediaParceledListSlice queue) { - mSessionStub.setQueue(queue == null ? null : queue.getList()); - } - - @Override - public void setQueueTitle(CharSequence title) { - mSessionStub.setQueueTitle(title); - } - - @Override - public void setExtras(Bundle extras) { - mSessionStub.setExtras(extras); - } - - @Override - public void setRatingType(int type) { - mSessionStub.setRatingType(type); - } - - @Override - public void setPlaybackToLocal(AudioAttributes attributes) { - mSessionStub.setPlaybackToLocal(attributes); - } - - @Override - public void setPlaybackToRemote(int control, int max) { - mSessionStub.setPlaybackToRemote(control, max); - } - - @Override - public void setCurrentVolume(int currentVolume) { - mSessionStub.setCurrentVolume(currentVolume); - } - } -} diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp index 365e045689f0..d28c15c98d16 100644 --- a/media/jni/android_media_MediaHTTPConnection.cpp +++ b/media/jni/android_media_MediaHTTPConnection.cpp @@ -109,7 +109,8 @@ static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) { gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); CHECK(gFields.context != NULL); - gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I"); + gFields.readAtMethodID = env->GetMethodID( + clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I"); } static void android_media_MediaHTTPConnection_native_setup( @@ -132,7 +133,7 @@ static jobject android_media_MediaHTTPConnection_native_getIMemory( } static jint android_media_MediaHTTPConnection_native_readAt( - JNIEnv *env, jobject thiz, jlong offset, jint size) { + JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) { sp<JMediaHTTPConnection> conn = getObject(env, thiz); if (size > JMediaHTTPConnection::kBufferSize) { size = JMediaHTTPConnection::kBufferSize; @@ -141,7 +142,7 @@ static jint android_media_MediaHTTPConnection_native_readAt( jbyteArray byteArrayObj = conn->getByteArrayObj(); jint n = env->CallIntMethod( - thiz, gFields.readAtMethodID, offset, byteArrayObj, size); + thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState); if (n > 0) { env->GetByteArrayRegion( @@ -158,7 +159,7 @@ static const JNINativeMethod gMethods[] = { { "native_getIMemory", "()Landroid/os/IBinder;", (void *)android_media_MediaHTTPConnection_native_getIMemory }, - { "native_readAt", "(JI)I", + { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I", (void *)android_media_MediaHTTPConnection_native_readAt }, { "native_init", "()V", diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index a288d010e59b..bda5743d27f7 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -52,6 +52,7 @@ import android.view.View; import android.webkit.CookieManager; import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; +import android.webkit.WebResourceRequest; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -409,8 +410,7 @@ public class CaptivePortalLoginActivity extends Activity { TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()); private int mPagesLoaded; - // the host of the page that this webview is currently loading. Can be null when undefined. - private String mHostname; + private String mMainFrameUrl; // If we haven't finished cleaning up the history, don't allow going back. public boolean allowBack() { @@ -436,7 +436,6 @@ public class CaptivePortalLoginActivity extends Activity { } final URL url = makeURL(urlString); Log.d(TAG, "onPageStarted: " + sanitizeURL(url)); - mHostname = host(url); // For internally generated pages, leave URL bar listing prior URL as this is the URL // the page refers to. if (!urlString.startsWith(INTERNAL_ASSETS)) { @@ -480,17 +479,28 @@ public class CaptivePortalLoginActivity extends Activity { return Integer.toString((int)dp) + "px"; } + // Check if webview is trying to load the main frame and record its url. + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + if (request.isForMainFrame()) { + mMainFrameUrl = request.getUrl().toString(); + } + return false; + } + // A web page consisting of a large broken lock icon to indicate SSL failure. @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { - final URL url = makeURL(error.getUrl()); - final String host = host(url); + final URL errorUrl = makeURL(error.getUrl()); + final URL mainFrameUrl = makeURL(mMainFrameUrl); Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s", - sslErrorName(error), sanitizeURL(url), error.getCertificate())); - if (url == null || !Objects.equals(host, mHostname)) { - // Ignore ssl errors for resources coming from a different hostname than the page - // that we are currently loading, and only cancel the request. + sslErrorName(error), sanitizeURL(errorUrl), error.getCertificate())); + if (errorUrl == null + // Ignore SSL errors from resources by comparing the main frame url with SSL + // error url. + || !errorUrl.equals(mainFrameUrl)) { + Log.d(TAG, "onReceivedSslError: mMainFrameUrl = " + mMainFrameUrl); handler.cancel(); return; } diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index 9064ebe80da1..4c9629def113 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -58,8 +58,8 @@ android_app { manifest: "AndroidManifest.xml", - owner: "google", platform_apis: true, + product_specific: true, certificate: "platform", privileged: true, @@ -82,4 +82,6 @@ android_app { ], plugins: ["dagger2-compiler-2.19"], + + required: ["privapp_whitelist_com.android.systemui"], } diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index 190247aecb2e..8872147b65ed 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -25,6 +25,7 @@ android_library { ":services-networkstack-shared-srcs", ], static_libs: [ + "ipmemorystore-client", "netd_aidl_interface-java", "networkstack-aidl-interfaces-java", "datastallprotosnano", diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt index a8c712a3336d..7346b1ae81e6 100644 --- a/packages/NetworkStack/jarjar-rules-shared.txt +++ b/packages/NetworkStack/jarjar-rules-shared.txt @@ -8,12 +8,3 @@ rule android.net.shared.InetAddressUtils* android.net.networkstack.shared.InetAd rule android.net.DhcpResultsParcelable* @0 rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1 rule android.net.LocalLog* android.net.networkstack.LocalLog@1 - -# TODO: remove from framework dependencies, then remove here -rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1 -rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1 - -# Used by UidRange, which is used by framework classes such as NetworkCapabilities. -rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1 -# TODO: move TcpKeepalivePacketData to services.net and delete -rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file diff --git a/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java new file mode 100644 index 000000000000..475f8261fdc1 --- /dev/null +++ b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java @@ -0,0 +1,42 @@ +/* + * 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 android.net; + +import android.annotation.NonNull; +import android.content.Context; + +/** + * service used to communicate with the ip memory store service in network stack, + * which is running in the same module. + * @see com.android.server.connectivity.ipmemorystore.IpMemoryStoreService + * @hide + */ +public class NetworkStackIpMemoryStore extends IpMemoryStoreClient { + @NonNull private final IIpMemoryStore mService; + + public NetworkStackIpMemoryStore(@NonNull final Context context, + @NonNull final IIpMemoryStore service) { + super(context); + mService = service; + } + + @Override + @NonNull + protected IIpMemoryStore getService() { + return mService; + } +} diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java index 7c7cdbdb8530..b68fe235647a 100644 --- a/packages/NetworkStack/src/android/net/ip/IpClient.java +++ b/packages/NetworkStack/src/android/net/ip/IpClient.java @@ -29,6 +29,7 @@ import android.net.INetd; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.NetworkStackIpMemoryStore; import android.net.ProvisioningConfigurationParcelable; import android.net.ProxyInfo; import android.net.RouteInfo; @@ -61,6 +62,7 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; import com.android.server.NetworkObserverRegistry; +import com.android.server.NetworkStackService.NetworkStackServiceManager; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -100,6 +102,7 @@ public class IpClient extends StateMachine { // One holds StateMachine logs and the other connectivity packet logs. private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>(); + private final NetworkStackIpMemoryStore mIpMemoryStore; /** * Dump all state machine and connectivity packet logs to the specified writer. @@ -388,13 +391,14 @@ public class IpClient extends StateMachine { } public IpClient(Context context, String ifName, IIpClientCallbacks callback, - NetworkObserverRegistry observerRegistry) { - this(context, ifName, callback, observerRegistry, new Dependencies()); + NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) { + this(context, ifName, callback, observerRegistry, nssManager, new Dependencies()); } @VisibleForTesting IpClient(Context context, String ifName, IIpClientCallbacks callback, - NetworkObserverRegistry observerRegistry, Dependencies deps) { + NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager, + Dependencies deps) { super(IpClient.class.getSimpleName() + "." + ifName); Preconditions.checkNotNull(ifName); Preconditions.checkNotNull(callback); @@ -408,6 +412,8 @@ public class IpClient extends StateMachine { mShutdownLatch = new CountDownLatch(1); mCm = mContext.getSystemService(ConnectivityManager.class); mObserverRegistry = observerRegistry; + mIpMemoryStore = + new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService()); sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag)); mLog = sSmLogs.get(mInterfaceName); diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java index e7c8e8578f81..335d9513bddb 100644 --- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java +++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java @@ -29,6 +29,8 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.IIpMemoryStore; +import android.net.IIpMemoryStoreCallbacks; import android.net.INetd; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; @@ -49,6 +51,7 @@ import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.connectivity.NetworkMonitor; +import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -86,7 +89,19 @@ public class NetworkStackService extends Service { return makeConnector(this); } - private static class NetworkStackConnector extends INetworkStackConnector.Stub { + /** + * An interface for internal clients of the network stack service that can return + * or create inline instances of the service it manages. + */ + public interface NetworkStackServiceManager { + /** + * Get an instance of the IpMemoryStoreService. + */ + IIpMemoryStore getIpMemoryStoreService(); + } + + private static class NetworkStackConnector extends INetworkStackConnector.Stub + implements NetworkStackServiceManager { private static final int NUM_VALIDATION_LOG_LINES = 20; private final Context mContext; private final INetd mNetd; @@ -94,6 +109,7 @@ public class NetworkStackService extends Service { private final ConnectivityManager mCm; @GuardedBy("mIpClients") private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>(); + private final IpMemoryStoreService mIpMemoryStoreService; private static final int MAX_VALIDATION_LOGS = 10; @GuardedBy("mValidationLogs") @@ -116,6 +132,7 @@ public class NetworkStackService extends Service { (IBinder) context.getSystemService(Context.NETD_SERVICE)); mObserverRegistry = new NetworkObserverRegistry(); mCm = context.getSystemService(ConnectivityManager.class); + mIpMemoryStoreService = new IpMemoryStoreService(context); try { mObserverRegistry.register(mNetd); @@ -159,7 +176,7 @@ public class NetworkStackService extends Service { @Override public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException { - final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry); + final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry, this); synchronized (mIpClients) { final Iterator<WeakReference<IpClient>> it = mIpClients.iterator(); @@ -176,6 +193,17 @@ public class NetworkStackService extends Service { } @Override + public IIpMemoryStore getIpMemoryStoreService() { + return mIpMemoryStoreService; + } + + @Override + public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb) + throws RemoteException { + cb.onIpMemoryStoreFetched(mIpMemoryStoreService); + } + + @Override protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args) { checkDumpPermission(); diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index b238ae4a066a..9d91487fec82 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -1615,12 +1615,12 @@ public class NetworkMonitor extends StateMachine { return; } // See if the data sub is registered for PS services on cell. - final NetworkRegistrationInfo nrs = dataSs.getNetworkRegistrationInfo( + final NetworkRegistrationInfo nri = dataSs.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); latencyBroadcast.putExtra( NetworkMonitorUtils.EXTRA_CELL_ID, - nrs == null ? null : nrs.getCellIdentity()); + nri == null ? null : nri.getCellIdentity()); latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE); } else { return; diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java index bbecc6359a40..4d4ceed9cb52 100644 --- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java index d43dc6a24260..f801b355c43e 100644 --- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package com.android.server.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; import static android.net.ipmemorystore.Status.ERROR_DATABASE_CANNOT_BE_OPENED; import static android.net.ipmemorystore.Status.ERROR_GENERIC; import static android.net.ipmemorystore.Status.ERROR_ILLEGAL_ARGUMENT; import static android.net.ipmemorystore.Status.SUCCESS; -import static com.android.server.net.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR; +import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,7 +40,6 @@ import android.net.ipmemorystore.NetworkAttributesParcelable; import android.net.ipmemorystore.SameL3NetworkResponse; import android.net.ipmemorystore.Status; import android.net.ipmemorystore.StatusParcelable; -import android.net.ipmemorystore.Utils; import android.os.RemoteException; import android.util.Log; diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java index aa454008958d..38d55448aa2a 100644 --- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; import com.android.internal.annotations.VisibleForTesting; diff --git a/core/java/android/net/ipmemorystore/Utils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java index b361aca5a6f7..9cbf490505f4 100644 --- a/core/java/android/net/ipmemorystore/Utils.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package android.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.ipmemorystore.Blob; /** {@hide} */ public class Utils { diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java index 4536c473915a..eee12d6f8c7c 100644 --- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java +++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java @@ -51,6 +51,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.server.NetworkObserver; import com.android.server.NetworkObserverRegistry; +import com.android.server.NetworkStackService; import org.junit.Before; import org.junit.Test; @@ -90,6 +91,7 @@ public class IpClientTest { @Mock private AlarmManager mAlarm; @Mock private IpClient.Dependencies mDependencies; @Mock private ContentResolver mContentResolver; + @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager; private NetworkObserver mObserver; private InterfaceParams mIfParams; @@ -118,7 +120,8 @@ public class IpClientTest { private IpClient makeIpClient(String ifname) throws Exception { setTestInterfaceParams(ifname); - final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies); + final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, + mNetworkStackServiceManager, mDependencies); verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false); verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname); ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class); @@ -142,8 +145,8 @@ public class IpClientTest { public void testNullInterfaceNameMostDefinitelyThrows() throws Exception { setTestInterfaceParams(null); try { - final IpClient ipc = new IpClient( - mContext, null, mCb, mObserverRegistry, mDependencies); + final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry, + mNetworkStackServiceManager, mDependencies); ipc.shutdown(); fail(); } catch (NullPointerException npe) { @@ -156,8 +159,8 @@ public class IpClientTest { final String ifname = "lo"; setTestInterfaceParams(ifname); try { - final IpClient ipc = new IpClient( - mContext, ifname, null, mObserverRegistry, mDependencies); + final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry, + mNetworkStackServiceManager, mDependencies); ipc.shutdown(); fail(); } catch (NullPointerException npe) { @@ -168,16 +171,16 @@ public class IpClientTest { @Test public void testInvalidInterfaceDoesNotThrow() throws Exception { setTestInterfaceParams(TEST_IFNAME); - final IpClient ipc = new IpClient( - mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies); + final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry, + mNetworkStackServiceManager, mDependencies); ipc.shutdown(); } @Test public void testInterfaceNotFoundFailsImmediately() throws Exception { setTestInterfaceParams(null); - final IpClient ipc = new IpClient( - mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies); + final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry, + mNetworkStackServiceManager, mDependencies); ipc.startProvisioning(new ProvisioningConfiguration()); verify(mCb, times(1)).onProvisioningFailure(any()); ipc.shutdown(); diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java index be1068065b05..d0e58b817e9d 100644 --- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java index 7413b914dbe9..3d3aabc66e70 100644 --- a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.server.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; -import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE; +import static com.android.server.connectivity.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index 591cf7071e01..a69b41258974 100644 --- a/packages/PackageInstaller/AndroidManifest.xml +++ b/packages/PackageInstaller/AndroidManifest.xml @@ -93,6 +93,7 @@ <activity android:name=".UninstallerActivity" android:configChanges="orientation|keyboardHidden|screenSize" + android:theme="@style/Theme.AlertDialogActivity.NoActionBar" android:excludeFromRecents="true" android:noHistory="true"> <intent-filter android:priority="1"> diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml index 6c8e4c551476..b11d28bac664 100644 --- a/packages/PackageInstaller/res/values/themes.xml +++ b/packages/PackageInstaller/res/values/themes.xml @@ -24,4 +24,9 @@ <style name="Theme.AlertDialogActivity" parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" /> + <style name="Theme.AlertDialogActivity.NoActionBar"> + <item name="android:windowActionBar">false</item> + <item name="android:windowNoTitle">true</item> + </style> + </resources> diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml index e27ae7d6d439..da575dbd7fac 100644 --- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml +++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml @@ -21,6 +21,8 @@ style="@style/EntityHeader" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:orientation="horizontal"> <LinearLayout diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java index 8529e3ef8420..87b5b57c7d9e 100644 --- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java +++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java @@ -20,6 +20,7 @@ import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -47,7 +48,16 @@ public class RestrictedLockUtils { if (dpm == null) { return null; } - ComponentName adminComponent = dpm.getProfileOwnerAsUser(user); + + Context userContext; + try { + userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalStateException(e); + } + + ComponentName adminComponent = userContext.getSystemService( + DevicePolicyManager.class).getProfileOwner(); if (adminComponent != null) { return new EnforcedAdmin(adminComponent, enforcedRestriction, user); } diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index bf97d772bb0b..d3dde92a4b44 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -185,8 +185,12 @@ <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level. [CHAR LIMIT=NONE] --> <string name="bluetooth_active_battery_level">Active, <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string> + <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] --> + <string name="bluetooth_active_battery_level_untethered">Active, L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string> <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] --> <string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string> + <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset. [CHAR LIMIT=NONE] --> + <string name="bluetooth_battery_level_untethered">L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string> <!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] --> <string name="bluetooth_active_no_battery_level">Active</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index c9fbc7ba9f05..d4d0519fcc5f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -128,12 +128,12 @@ public class ApplicationsState { // to protect access to these. final ArrayList<Session> mSessions = new ArrayList<Session>(); final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>(); - final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges(); + private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges(); // Map: userid => (Map: package name => AppEntry) final SparseArray<HashMap<String, AppEntry>> mEntriesMap = new SparseArray<HashMap<String, AppEntry>>(); final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>(); - List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>(); + List<ApplicationInfo> mApplications = new ArrayList<>(); long mCurId = 1; UUID mCurComputingSizeUuid; String mCurComputingSizePkg; @@ -166,7 +166,7 @@ public class ApplicationsState { /** * Flags to configure the session to request various types of info. */ - @IntDef(prefix = { "FLAG_SESSION_" }, value = { + @IntDef(prefix = {"FLAG_SESSION_"}, value = { FLAG_SESSION_REQUEST_HOME_APP, FLAG_SESSION_REQUEST_ICONS, FLAG_SESSION_REQUEST_SIZES, @@ -174,7 +174,13 @@ public class ApplicationsState { FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER }) @Retention(RetentionPolicy.SOURCE) - public @interface SessionFlags {} + public @interface SessionFlags { + } + + @VisibleForTesting + void setInterestingConfigChanges(InterestingConfigChanges interestingConfigChanges) { + mInterestingConfigChanges = interestingConfigChanges; + } public static final @SessionFlags int DEFAULT_SESSION_FLAGS = FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS | @@ -190,6 +196,7 @@ public class ApplicationsState { for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) { mEntriesMap.put(userId, new HashMap<String, AppEntry>()); } + mThread = new HandlerThread("ApplicationsState.Loader", Process.THREAD_PRIORITY_BACKGROUND); mThread.start(); @@ -256,12 +263,14 @@ public class ApplicationsState { mPackageIntentReceiver = new PackageIntentReceiver(); mPackageIntentReceiver.registerReceiver(); } - mApplications = new ArrayList<ApplicationInfo>(); + + final List<ApplicationInfo> prevApplications = mApplications; + mApplications = new ArrayList<>(); for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) { try { // If this user is new, it needs a map created. if (mEntriesMap.indexOfKey(user.id) < 0) { - mEntriesMap.put(user.id, new HashMap<String, AppEntry>()); + mEntriesMap.put(user.id, new HashMap<>()); } @SuppressWarnings("unchecked") ParceledListSlice<ApplicationInfo> list = @@ -279,14 +288,14 @@ public class ApplicationsState { // should completely reload the app entries. clearEntries(); } else { - for (int i=0; i<mAppEntries.size(); i++) { + for (int i = 0; i < mAppEntries.size(); i++) { mAppEntries.get(i).sizeStale = true; } } mHaveDisabledApps = false; mHaveInstantApps = false; - for (int i=0; i<mApplications.size(); i++) { + for (int i = 0; i < mApplications.size(); i++) { final ApplicationInfo info = mApplications.get(i); // Need to trim out any applications that are disabled by // something different than the user. @@ -312,8 +321,9 @@ public class ApplicationsState { entry.info = info; } } - if (mAppEntries.size() > mApplications.size()) { - // There are less apps now, some must have been uninstalled. + + if (anyAppIsRemoved(prevApplications, mApplications)) { + // some apps have been uninstalled. clearEntries(); } mCurComputingSizePkg = null; @@ -322,6 +332,82 @@ public class ApplicationsState { } } + /* The original design is mAppEntries.size() > mApplications.size(). + It's correct if there is only the owner user and only one app is removed. + Problem 1: + If there is a user profile, the size of mAppEntries < mApplications is normal because + the number of app entries on UI (mAppEntries) should be equal to the number of apps got + from PMS (mApplications). + + owner only case: + mApplications: user 0: 191 + mAppEntries : user 0: 191 + total mAppEntries: 191, mApplications: 191 + If an app is removed, cached mAppEntries: 191 , mApplications: 191 -> 190, it is detected + as the number of apps becomes less. + + If there is a work profile, mAppEntries removes some apps that are not installed for the + owner user. + + For example, in the following case, 6 apps are removed from mAppEntries for the owner. + mApplications: user 0: 197, user 10: 189 => total 386 + mAppEntries : user 0: 191, user 10: 189 => total 380 + If an app is removed, cached mAppEntries: 380 , mApplications: 386 -> 385, the size of + mAppEntries is still not larger than mApplications, then does not clear mAppEntries. + + Problem 2: + If remove an app and add another app outside Settings (e.g. Play Store) and back to + Settings, the amount of apps are not changed, it causes the entries keep the removed app. + + Another case, if adding more apps than removing apps (e.g. add 2 apps and remove 1 app), + the final number of apps (mApplications) is even increased, + + Therefore, should not only count on number of apps to determine any app is removed. + Compare the change of applications instead. + */ + private static boolean anyAppIsRemoved(List<ApplicationInfo> prevApplications, + List<ApplicationInfo> applications) { + + // No cache + if (prevApplications.size() == 0) { + return false; + } + + if (applications.size() < prevApplications.size()) { + return true; + } + + // build package sets of all applications <userId, HashSet of packages> + final HashMap<String, HashSet<String>> packageMap = new HashMap<>(); + for (ApplicationInfo application : applications) { + final String userId = String.valueOf(UserHandle.getUserId(application.uid)); + + HashSet<String> appPackages = packageMap.get(userId); + if (appPackages == null) { + appPackages = new HashSet<>(); + packageMap.put(userId, appPackages); + } + if (hasFlag(application.flags, ApplicationInfo.FLAG_INSTALLED)) { + appPackages.add(application.packageName); + } + } + + // detect any previous app is removed + for (ApplicationInfo prevApplication : prevApplications) { + if (!hasFlag(prevApplication.flags, ApplicationInfo.FLAG_INSTALLED)) { + continue; + } + final String userId = String.valueOf(UserHandle.getUserId(prevApplication.uid)); + + final HashSet<String> packagesSet = packageMap.get(userId); + if (packagesSet == null || !packagesSet.remove(prevApplication.packageName)) { + return true; + } + } + + return false; + } + @VisibleForTesting void clearEntries() { for (int i = 0; i < mEntriesMap.size(); i++) { @@ -346,7 +432,7 @@ public class ApplicationsState { if (!mResumed) { return; } - for (int i=0; i<mSessions.size(); i++) { + for (int i = 0; i < mSessions.size(); i++) { if (mSessions.get(i).mResumed) { return; } @@ -449,7 +535,7 @@ public class ApplicationsState { if (DEBUG_LOCKING) Log.v(TAG, "sumCacheSizes about to acquire lock..."); synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "-> sumCacheSizes now has lock"); - for (int i=mAppEntries.size()-1; i>=0; i--) { + for (int i = mAppEntries.size() - 1; i >= 0; i--) { sum += mAppEntries.get(i).cacheSize; } if (DEBUG_LOCKING) Log.v(TAG, "...sumCacheSizes releasing lock"); @@ -458,7 +544,7 @@ public class ApplicationsState { } int indexOfApplicationInfoLocked(String pkgName, int userId) { - for (int i=mApplications.size()-1; i>=0; i--) { + for (int i = mApplications.size() - 1; i >= 0; i--) { ApplicationInfo appInfo = mApplications.get(i); if (appInfo.packageName.equals(pkgName) && UserHandle.getUserId(appInfo.uid) == userId) { @@ -642,7 +728,7 @@ public class ApplicationsState { return; } mActiveSessions.clear(); - for (int i=0; i<mSessions.size(); i++) { + for (int i = 0; i < mSessions.size(); i++) { Session s = mSessions.get(i); if (s.mResumed) { mActiveSessions.add(new WeakReference<>(s)); @@ -784,7 +870,7 @@ public class ApplicationsState { ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>(); if (DEBUG) Log.i(TAG, "Rebuilding..."); - for (int i=0; i<apps.size(); i++) { + for (int i = 0; i < apps.size(); i++) { AppEntry entry = apps.get(i); if (entry != null && (filter == null || filter.filterApp(entry))) { synchronized (mEntriesMap) { @@ -954,7 +1040,7 @@ public class ApplicationsState { } } if (rebuildingSessions != null) { - for (int i=0; i<rebuildingSessions.size(); i++) { + for (int i = 0; i < rebuildingSessions.size(); i++) { rebuildingSessions.get(i).handleRebuildList(); } } @@ -1047,9 +1133,9 @@ public class ApplicationsState { // If we do not specify MATCH_DIRECT_BOOT_AWARE or // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags // according to the user's lock state. When the user is locked, - // components - // with ComponentInfo#directBootAware == false will be filtered. We should - // explicitly include both direct boot aware and unaware components here. + // components with ComponentInfo#directBootAware == false will be + // filtered. W should explicitly include both direct boot aware and + // unaware component here. List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser( launchIntent, PackageManager.MATCH_DISABLED_COMPONENTS @@ -1128,8 +1214,10 @@ public class ApplicationsState { synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES acquired lock"); if (mCurComputingSizePkg != null) { - if (DEBUG_LOCKING) Log.v(TAG, - "MSG_LOAD_SIZES releasing: currently computing"); + if (DEBUG_LOCKING) { + Log.v(TAG, + "MSG_LOAD_SIZES releasing: currently computing"); + } return; } @@ -1181,8 +1269,10 @@ public class ApplicationsState { }); } - if (DEBUG_LOCKING) Log.v(TAG, - "MSG_LOAD_SIZES releasing: now computing"); + if (DEBUG_LOCKING) { + Log.v(TAG, + "MSG_LOAD_SIZES releasing: now computing"); + } return; } } @@ -1255,8 +1345,10 @@ public class ApplicationsState { entry.internalSizeStr = getSizeStr(entry.internalSize); entry.externalSize = getTotalExternalSize(stats); entry.externalSizeStr = getSizeStr(entry.externalSize); - if (DEBUG) Log.i(TAG, "Set size of " + entry.label + " " + entry - + ": " + entry.sizeStr); + if (DEBUG) { + Log.i(TAG, "Set size of " + entry.label + " " + entry + + ": " + entry.sizeStr); + } sizeChanged = true; } } @@ -1299,9 +1391,11 @@ public class ApplicationsState { userFilter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(this, userFilter); } + void unregisterReceiver() { mContext.unregisterReceiver(this); } + @Override public void onReceive(Context context, Intent intent) { String actionStr = intent.getAction(); @@ -1354,12 +1448,19 @@ public class ApplicationsState { public interface Callbacks { void onRunningStateChanged(boolean running); + void onPackageListChanged(); + void onRebuildComplete(ArrayList<AppEntry> apps); + void onPackageIconChanged(); + void onPackageSizeChanged(String packageName); + void onAllSizesComputed(); + void onLauncherInfoChanged(); + void onLoadEntriesCompleted(); } @@ -1491,6 +1592,7 @@ public class ApplicationsState { */ public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() { private final Collator sCollator = Collator.getInstance(); + @Override public int compare(AppEntry object1, AppEntry object2) { int compareResult = sCollator.compare(object1.label, object2.label); @@ -1504,6 +1606,7 @@ public class ApplicationsState { return compareResult; } } + return object1.info.uid - object2.info.uid; } }; @@ -1540,9 +1643,11 @@ public class ApplicationsState { public interface AppFilter { void init(); + default void init(Context context) { init(); } + boolean filterApp(AppEntry info); } @@ -1697,7 +1802,8 @@ public class ApplicationsState { @Override public boolean filterApp(AppEntry entry) { return !AppUtils.isInstant(entry.info) - && hasFlag(entry.info.privateFlags, ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS); + && hasFlag(entry.info.privateFlags, + ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS); } }; @@ -1707,7 +1813,7 @@ public class ApplicationsState { @Override public void init(Context context) { mHidePackageNames = context.getResources() - .getStringArray(R.array.config_hideWhenDisabled_packageNames); + .getStringArray(R.array.config_hideWhenDisabled_packageNames); } @Override @@ -1720,7 +1826,7 @@ public class ApplicationsState { if (!entry.info.enabled) { return false; } else if (entry.info.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { return false; } } @@ -1798,7 +1904,7 @@ public class ApplicationsState { @Override public boolean filterApp(AppEntry entry) { boolean isMusicApp; - synchronized(entry) { + synchronized (entry) { isMusicApp = entry.info.category == ApplicationInfo.CATEGORY_AUDIO; } return isMusicApp; @@ -1813,7 +1919,7 @@ public class ApplicationsState { @Override public boolean filterApp(AppEntry entry) { boolean isMovieApp; - synchronized(entry) { + synchronized (entry) { isMovieApp = entry.info.category == ApplicationInfo.CATEGORY_VIDEO; } return isMovieApp; @@ -1823,7 +1929,8 @@ public class ApplicationsState { public static final AppFilter FILTER_PHOTOS = new AppFilter() { @Override - public void init() {} + public void init() { + } @Override public boolean filterApp(AppEntry entry) { @@ -1838,7 +1945,8 @@ public class ApplicationsState { public static final AppFilter FILTER_OTHER_APPS = new AppFilter() { @Override - public void init() {} + public void init() { + } @Override public boolean filterApp(AppEntry entry) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index 081f8a099cf5..bb8c8a6768ed 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -1,7 +1,6 @@ package com.android.settingslib.bluetooth; import android.bluetooth.BluetoothClass; -import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.graphics.drawable.Drawable; @@ -10,7 +9,6 @@ import android.util.Pair; import androidx.annotation.DrawableRes; import com.android.settingslib.R; -import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; import java.util.List; @@ -51,38 +49,29 @@ public class BluetoothUtils { public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context, CachedBluetoothDevice cachedDevice) { - return getBtClassDrawableWithDescription(context, cachedDevice, 1 /* iconScale */); - } - - public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context, - CachedBluetoothDevice cachedDevice, float iconScale) { BluetoothClass btClass = cachedDevice.getBtClass(); - final int level = cachedDevice.getBatteryLevel(); if (btClass != null) { switch (btClass.getMajorDeviceClass()) { case BluetoothClass.Device.Major.COMPUTER: return new Pair<>(getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_bt_laptop, level, iconScale), + com.android.internal.R.drawable.ic_bt_laptop), context.getString(R.string.bluetooth_talkback_computer)); case BluetoothClass.Device.Major.PHONE: return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_phone, level, - iconScale), + com.android.internal.R.drawable.ic_phone), context.getString(R.string.bluetooth_talkback_phone)); case BluetoothClass.Device.Major.PERIPHERAL: return new Pair<>( - getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass), - level, iconScale), + getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass)), context.getString(R.string.bluetooth_talkback_input_peripheral)); case BluetoothClass.Device.Major.IMAGING: return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_settings_print, level, - iconScale), + com.android.internal.R.drawable.ic_settings_print), context.getString(R.string.bluetooth_talkback_imaging)); default: @@ -94,38 +83,33 @@ public class BluetoothUtils { for (LocalBluetoothProfile profile : profiles) { int resId = profile.getDrawableResource(btClass); if (resId != 0) { - return new Pair<>(getBluetoothDrawable(context, resId, level, iconScale), null); + return new Pair<>(getBluetoothDrawable(context, resId), null); } } if (btClass != null) { if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_bt_headset_hfp, level, - iconScale), + com.android.internal.R.drawable.ic_bt_headset_hfp), context.getString(R.string.bluetooth_talkback_headset)); } if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_bt_headphones_a2dp, level, - iconScale), + com.android.internal.R.drawable.ic_bt_headphones_a2dp), context.getString(R.string.bluetooth_talkback_headphone)); } } return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_settings_bluetooth, level, iconScale), + com.android.internal.R.drawable.ic_settings_bluetooth), context.getString(R.string.bluetooth_talkback_bluetooth)); } - public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId, - int batteryLevel, float iconScale) { - if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { - return BluetoothDeviceLayerDrawable.createLayerDrawable(context, resId, batteryLevel, - iconScale); - } else { - return context.getDrawable(resId); - } + /** + * Get bluetooth drawable by {@code resId} + */ + public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId) { + return context.getDrawable(resId); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index ab95910a77b5..2405666af500 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -32,6 +32,7 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settingslib.R; +import com.android.settingslib.Utils; import java.util.ArrayList; import java.util.Collection; @@ -830,6 +831,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean a2dpConnected = true; // A2DP is connected boolean hfpConnected = true; // HFP is connected boolean hearingAidConnected = true; // Hearing Aid is connected + int leftBattery = -1; + int rightBattery = -1; synchronized (mProfileLock) { for (LocalBluetoothProfile profile : getProfiles()) { @@ -877,8 +880,23 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> int stringRes = R.string.bluetooth_pairing; //when profile is connected, information would be available if (profileConnected) { + // Update Meta data for connected device + if (Boolean.parseBoolean( + mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))) { + try { + leftBattery = Integer.parseInt( + mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)); + rightBattery = Integer.parseInt(mDevice.getMetadata( + BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)); + } catch (NumberFormatException e) { + Log.d(TAG, "Parse error for unthethered battery level."); + } + } + // Set default string with battery level in device connected situation. - if (batteryLevelPercentageString != null) { + if (isTwsBatteryAvailable(leftBattery, rightBattery)) { + stringRes = R.string.bluetooth_battery_level_untethered; + } else if (batteryLevelPercentageString != null) { stringRes = R.string.bluetooth_battery_level; } @@ -887,22 +905,36 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // 2. Headset device active with in-calling state. // 3. A2DP device active without in-calling state. if (a2dpConnected || hfpConnected || hearingAidConnected) { - final boolean isOnCall = - com.android.settingslib.Utils.isAudioModeOngoingCall(mContext); + final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext); if ((mIsActiveDeviceHearingAid) || (mIsActiveDeviceHeadset && isOnCall) || (mIsActiveDeviceA2dp && !isOnCall)) { - stringRes = (batteryLevelPercentageString != null) - ? R.string.bluetooth_active_battery_level - : R.string.bluetooth_active_no_battery_level; + if (isTwsBatteryAvailable(leftBattery, rightBattery)) { + stringRes = R.string.bluetooth_active_battery_level_untethered; + } else if (batteryLevelPercentageString != null) { + stringRes = R.string.bluetooth_active_battery_level; + } else { + stringRes = R.string.bluetooth_active_no_battery_level; + } } } } - return (stringRes != R.string.bluetooth_pairing - || getBondState() == BluetoothDevice.BOND_BONDING) - ? mContext.getString(stringRes, batteryLevelPercentageString) - : null; + if (stringRes != R.string.bluetooth_pairing + || getBondState() == BluetoothDevice.BOND_BONDING) { + if (isTwsBatteryAvailable(leftBattery, rightBattery)) { + return mContext.getString(stringRes, Utils.formatPercentage(leftBattery), + Utils.formatPercentage(rightBattery)); + } else { + return mContext.getString(stringRes, batteryLevelPercentageString); + } + } else { + return null; + } + } + + private boolean isTwsBatteryAvailable(int leftBattery, int rightBattery) { + return leftBattery >= 0 && rightBattery >= 0; } /** diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java index bee1b3cb7df5..d28b00a7ed39 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java @@ -276,6 +276,12 @@ public class Tile implements Parcelable { return null; } ensureMetadataNotStale(context); + final ActivityInfo activityInfo = getActivityInfo(context); + if (activityInfo == null) { + Log.w(TAG, "Cannot find ActivityInfo for " + getDescription()); + return null; + } + int iconResId = mMetaData.getInt(META_DATA_PREFERENCE_ICON); // Set the icon if (iconResId == 0) { @@ -283,11 +289,11 @@ public class Tile implements Parcelable { // ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this // level is too complex because we don't have a strong threading contract for this class if (!mMetaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) { - iconResId = getActivityInfo(context).icon; + iconResId = activityInfo.icon; } } if (iconResId != 0) { - return Icon.createWithResource(getActivityInfo(context).packageName, iconResId); + return Icon.createWithResource(activityInfo.packageName, iconResId); } else { return null; } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java index da140aa9371e..8c3fcc077edc 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java @@ -70,13 +70,18 @@ public class PhoneMediaDevice extends MediaDevice { final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile(); final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); + // Some device may not have HearingAidProfile, consider all situation to set active device. boolean isConnected = false; - if (hapProfile != null && a2dpProfile != null) { isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null); - updateSummary(true); - setConnectedRecord(); + } else if (a2dpProfile != null) { + isConnected = a2dpProfile.setActiveDevice(null); + } else if (hapProfile != null) { + isConnected = hapProfile.setActiveDevice(null); } + updateSummary(isConnected); + setConnectedRecord(); + Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected); return isConnected; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java index a098ecc17b3d..b27efd0edc8b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java @@ -16,11 +16,17 @@ package com.android.settingslib.applications; +import static android.os.UserHandle.MU_ENABLED; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.shadow.api.Shadow.extract; @@ -40,10 +46,13 @@ import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; +import android.content.res.Resources; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; +import android.os.RemoteException; import android.os.UserHandle; +import android.os.UserManager; import android.text.TextUtils; import android.util.IconDrawableFactory; @@ -70,6 +79,7 @@ import org.robolectric.shadows.ShadowContextImpl; import org.robolectric.shadows.ShadowLooper; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.UUID; @@ -82,6 +92,19 @@ public class ApplicationsStateRoboTest { private final static String HOME_PACKAGE_NAME = "com.android.home"; private final static String LAUNCHABLE_PACKAGE_NAME = "com.android.launchable"; + private static final int PROFILE_USERID = 10; + + private static final String PKG_1 = "PKG1"; + private static final int OWNER_UID_1 = 1001; + private static final int PROFILE_UID_1 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_1); + + private static final String PKG_2 = "PKG2"; + private static final int OWNER_UID_2 = 1002; + private static final int PROFILE_UID_2 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_2); + + private static final String PKG_3 = "PKG3"; + private static final int OWNER_UID_3 = 1003; + /** Class under test */ private ApplicationsState mApplicationsState; private Session mSession; @@ -171,7 +194,7 @@ public class ApplicationsStateRoboTest { storageStats.dataBytes = 20; storageStats.cacheBytes = 30; when(mStorageStatsManager.queryStatsForPackage(any(UUID.class), - anyString(), any(UserHandle.class))).thenReturn(storageStats); + anyString(), any(UserHandle.class))).thenReturn(storageStats); // Set up 3 installed apps, in which 1 is hidden module final List<ApplicationInfo> infos = new ArrayList<>(); @@ -195,11 +218,16 @@ public class ApplicationsStateRoboTest { } private ApplicationInfo createApplicationInfo(String packageName) { + return createApplicationInfo(packageName, 0); + } + + private ApplicationInfo createApplicationInfo(String packageName, int uid) { ApplicationInfo appInfo = new ApplicationInfo(); appInfo.sourceDir = "foo"; appInfo.flags |= ApplicationInfo.FLAG_INSTALLED; appInfo.storageUuid = UUID.randomUUID(); appInfo.packageName = packageName; + appInfo.uid = uid; return appInfo; } @@ -211,10 +239,14 @@ public class ApplicationsStateRoboTest { } private void addApp(String packageName, int id) { - ApplicationInfo appInfo = createApplicationInfo(packageName); + addApp(packageName, id, 0); + } + + private void addApp(String packageName, int id, int userId) { + ApplicationInfo appInfo = createApplicationInfo(packageName, id); AppEntry appEntry = createAppEntry(appInfo, id); mApplicationsState.mAppEntries.add(appEntry); - mApplicationsState.mEntriesMap.get(0).put(appInfo.packageName, appEntry); + mApplicationsState.mEntriesMap.get(userId).put(appInfo.packageName, appEntry); } private void processAllMessages() { @@ -351,4 +383,328 @@ public class ApplicationsStateRoboTest { assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3"); } + @Test + public void removeAndInstall_noWorkprofile_doResumeIfNeededLocked_shouldClearEntries() + throws RemoteException { + // scenario: only owner user + // (PKG_1, PKG_2) -> (PKG_2, PKG_3) + // PKG_1 is removed and PKG_3 is installed before app is resumed. + ApplicationsState.sInstance = null; + mApplicationsState = spy( + ApplicationsState + .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class))); + + // Previous Applications: + ApplicationInfo appInfo; + final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + prevAppList.add(appInfo); + mApplicationsState.mApplications = prevAppList; + + // Previous Entries: + // (PKG_1, PKG_2) + addApp(PKG_1, OWNER_UID_1, 0); + addApp(PKG_2, OWNER_UID_2, 0); + + // latest Applications: + // (PKG_2, PKG_3) + final ArrayList<ApplicationInfo> appList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + appList.add(appInfo); + appInfo = createApplicationInfo(PKG_3, OWNER_UID_3); + appList.add(appInfo); + setupDoResumeIfNeededLocked(appList, null); + + mApplicationsState.doResumeIfNeededLocked(); + + verify(mApplicationsState).clearEntries(); + } + + @Test + public void noAppRemoved_noWorkprofile_doResumeIfNeededLocked_shouldNotClearEntries() + throws RemoteException { + // scenario: only owner user + // (PKG_1, PKG_2) + ApplicationsState.sInstance = null; + mApplicationsState = spy( + ApplicationsState + .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class))); + + ApplicationInfo appInfo; + // Previous Applications + final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + prevAppList.add(appInfo); + mApplicationsState.mApplications = prevAppList; + + // Previous Entries: + // (pk1, PKG_2) + addApp(PKG_1, OWNER_UID_1, 0); + addApp(PKG_2, OWNER_UID_2, 0); + + // latest Applications: + // (PKG_2, PKG_3) + final ArrayList<ApplicationInfo> appList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + appList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + appList.add(appInfo); + setupDoResumeIfNeededLocked(appList, null); + + mApplicationsState.doResumeIfNeededLocked(); + + verify(mApplicationsState, never()).clearEntries(); + } + + @Test + public void removeProfileApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries() + throws RemoteException { + if (!MU_ENABLED) { + return; + } + // [Preconditions] + // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state + // 2 apps (PKG_1, PKG_2) for non-owner. + // + // [Actions] + // profile user's PKG_2 is removed before resume + // + // Applications: + // owner - (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2) + // profile - (PKG_1, PKG_2) -> (PKG_1) + // + // Previous Entries: + // owner - (PKG_2) + // profile - (PKG_1, PKG_2) + + ShadowUserManager shadowUserManager = Shadow + .extract(RuntimeEnvironment.application.getSystemService(UserManager.class)); + shadowUserManager.addProfile(PROFILE_USERID, "profile"); + + ApplicationsState.sInstance = null; + mApplicationsState = spy( + ApplicationsState + .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class))); + + ApplicationInfo appInfo; + // Previous Applications + // owner - (PKG_1 - uninstalled, PKG_2) + // profile - (PKG_1, PKG_2) + final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED; + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + prevAppList.add(appInfo); + + appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1); + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2); + prevAppList.add(appInfo); + + mApplicationsState.mApplications = prevAppList; + // Previous Entries: + // owner (PKG_2), profile (pk1, PKG_2) + // PKG_1 is not installed for owner, hence it's removed from entries + addApp(PKG_2, OWNER_UID_2, 0); + addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID); + addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID); + + // latest Applications: + // owner (PKG_1, PKG_2), profile (PKG_1) + // owner's PKG_1 is still listed and is in non-installed state + // profile user's PKG_2 is removed by a user before resume + //owner + final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED; + ownerAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + ownerAppList.add(appInfo); + //profile + appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1); + setupDoResumeIfNeededLocked(ownerAppList, new ArrayList<>(Arrays.asList(appInfo))); + + mApplicationsState.doResumeIfNeededLocked(); + + verify(mApplicationsState).clearEntries(); + } + + @Test + public void removeOwnerApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries() + throws RemoteException { + if (!MU_ENABLED) { + return; + } + // [Preconditions] + // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state + // 2 apps (PKG_1, PKG_2) for non-owner. + // + // [Actions] + // Owner user's PKG_2 is removed before resume + // + // Applications: + // owner - (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2 - uninstalled) + // profile - (PKG_1, PKG_2) -> (PKG_1, PKG_2) + // + // Previous Entries: + // owner - (PKG_2) + // profile - (PKG_1, PKG_2) + + ShadowUserManager shadowUserManager = Shadow + .extract(RuntimeEnvironment.application.getSystemService(UserManager.class)); + shadowUserManager.addProfile(PROFILE_USERID, "profile"); + + ApplicationsState.sInstance = null; + mApplicationsState = spy( + ApplicationsState + .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class))); + + ApplicationInfo appInfo; + // Previous Applications: + // owner - (PKG_1 - uninstalled, PKG_2) + // profile - (PKG_1, PKG_2) + final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED; + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + prevAppList.add(appInfo); + + appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1); + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2); + prevAppList.add(appInfo); + + mApplicationsState.mApplications = prevAppList; + + // Previous Entries: + // owner (PKG_2), profile (pk1, PKG_2) + // PKG_1 is not installed for owner, hence it's removed from entries + addApp(PKG_2, OWNER_UID_2, 0); + addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID); + addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID); + + // latest Applications: + // owner (PKG_1 - uninstalled, PKG_2 - uninstalled), profile (PKG_1, PKG_2) + // owner's PKG_1, PKG_2 is still listed and is in non-installed state + // profile user's PKG_2 is removed before resume + //owner + final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED; + ownerAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED; + ownerAppList.add(appInfo); + + //profile + final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1); + profileAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2); + profileAppList.add(appInfo); + setupDoResumeIfNeededLocked(ownerAppList, profileAppList); + + mApplicationsState.doResumeIfNeededLocked(); + + verify(mApplicationsState).clearEntries(); + } + + @Test + public void noAppRemoved_workprofileExists_doResumeIfNeededLocked_shouldNotClearEntries() + throws RemoteException { + if (!MU_ENABLED) { + return; + } + // [Preconditions] + // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state + // 2 apps (PKG_1, PKG_2) for non-owner. + // + // Applications: + // owner - (PKG_1 - uninstalled, PKG_2) + // profile - (PKG_1, PKG_2) + // + // Previous Entries: + // owner - (PKG_2) + // profile - (PKG_1, PKG_2) + + ShadowUserManager shadowUserManager = Shadow + .extract(RuntimeEnvironment.application.getSystemService(UserManager.class)); + shadowUserManager.addProfile(PROFILE_USERID, "profile"); + + ApplicationsState.sInstance = null; + mApplicationsState = spy( + ApplicationsState + .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class))); + + ApplicationInfo appInfo; + // Previous Applications: + // owner - (PKG_1 - uninstalled, PKG_2) + // profile - (PKG_1, PKG_2) + final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED; + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + prevAppList.add(appInfo); + + appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1); + prevAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2); + prevAppList.add(appInfo); + + mApplicationsState.mApplications = prevAppList; + // Previous Entries: + // owner (PKG_2), profile (pk1, PKG_2) + // PKG_1 is not installed for owner, hence it's removed from entries + addApp(PKG_2, OWNER_UID_2, 0); + addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID); + addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID); + + // latest Applications: + // owner (PKG_1 - uninstalled, PKG_2), profile (PKG_1, PKG_2) + // owner's PKG_1 is still listed and is in non-installed state + + // owner + final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, OWNER_UID_1); + appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED; + ownerAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, OWNER_UID_2); + ownerAppList.add(appInfo); + + // profile + final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>(); + appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1); + profileAppList.add(appInfo); + appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2); + profileAppList.add(appInfo); + setupDoResumeIfNeededLocked(ownerAppList, profileAppList); + + mApplicationsState.doResumeIfNeededLocked(); + + verify(mApplicationsState, never()).clearEntries(); + } + + private void setupDoResumeIfNeededLocked(ArrayList<ApplicationInfo> ownerApps, + ArrayList<ApplicationInfo> profileApps) + throws RemoteException { + + if (ownerApps != null) { + when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(0))) + .thenReturn(new ParceledListSlice<>(ownerApps)); + } + if (profileApps != null) { + when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(PROFILE_USERID))) + .thenReturn(new ParceledListSlice<>(profileApps)); + } + final InterestingConfigChanges configChanges = mock(InterestingConfigChanges.class); + when(configChanges.applyNewConfig(any(Resources.class))).thenReturn(false); + mApplicationsState.setInterestingConfigChanges(configChanges); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java index 7a71551bb367..b713e08eb67e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java @@ -15,36 +15,55 @@ */ package com.android.settingslib.bluetooth; -import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothClass; +import android.content.Context; import android.graphics.drawable.Drawable; +import android.util.Pair; -import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; - +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class BluetoothUtilsTest { + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private CachedBluetoothDevice mCachedBluetoothDevice; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + } + @Test - public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() { - final Drawable drawable = BluetoothUtils.getBluetoothDrawable( - RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop, - BluetoothDevice.BATTERY_LEVEL_UNKNOWN, 1 /* iconScale */); + public void getBtClassDrawableWithDescription_typePhone_returnPhoneDrawable() { + when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn( + BluetoothClass.Device.Major.PHONE); + final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription( + mContext, mCachedBluetoothDevice); - assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class); + verify(mContext).getDrawable(com.android.internal.R.drawable.ic_phone); } @Test - public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() { - final Drawable drawable = BluetoothUtils.getBluetoothDrawable( - RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop, - 10 /* batteryLevel */, 1 /* iconScale */); + public void getBtClassDrawableWithDescription_typeComputer_returnComputerDrawable() { + when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn( + BluetoothClass.Device.Major.COMPUTER); + final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription( + mContext, mCachedBluetoothDevice); - assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class); + verify(mContext).getDrawable(com.android.internal.R.drawable.ic_bt_laptop); } -} +}
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index 4e5d38ab5799..79b84b9e5829 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -41,14 +41,16 @@ import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class CachedBluetoothDeviceTest { - private final static String DEVICE_NAME = "TestName"; - private final static String DEVICE_ALIAS = "TestAlias"; - private final static String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF"; - private final static String DEVICE_ALIAS_NEW = "TestAliasNew"; - private final static short RSSI_1 = 10; - private final static short RSSI_2 = 11; - private final static boolean JUSTDISCOVERED_1 = true; - private final static boolean JUSTDISCOVERED_2 = false; + private static final String DEVICE_NAME = "TestName"; + private static final String DEVICE_ALIAS = "TestAlias"; + private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF"; + private static final String DEVICE_ALIAS_NEW = "TestAliasNew"; + private static final String TWS_BATTERY_LEFT = "15"; + private static final String TWS_BATTERY_RIGHT = "25"; + private static final short RSSI_1 = 10; + private static final short RSSI_2 = 11; + private static final boolean JUSTDISCOVERED_1 = true; + private static final boolean JUSTDISCOVERED_2 = false; @Mock private LocalBluetoothProfileManager mProfileManager; @Mock @@ -447,6 +449,41 @@ public class CachedBluetoothDeviceTest { } @Test + public void getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery() { + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn( + "true"); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn( + TWS_BATTERY_LEFT); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn( + TWS_BATTERY_RIGHT); + + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Active, L: 15% battery, R: 25% battery"); + } + + @Test + public void getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery() { + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn( + "true"); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn( + TWS_BATTERY_LEFT); + when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn( + TWS_BATTERY_RIGHT); + + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "L: 15% battery, R: 25% battery"); + } + + @Test public void getCarConnectionSummary_singleProfileConnectDisconnect() { // Test without battery level // Set PAN profile to be connected and test connection state summary diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java index 50a6a9d7be20..0752dc03f397 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java @@ -100,6 +100,30 @@ public class PhoneMediaDeviceTest { } @Test + public void connect_hearingAidProfileIsNullAndA2dpProfileNotNull_isConnectedReturnTrue() { + when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null); + + when(mA2dpProfile.setActiveDevice(null)).thenReturn(true); + assertThat(mPhoneMediaDevice.connect()).isTrue(); + } + + @Test + public void connect_hearingAidProfileNotNullAndA2dpProfileIsNull_isConnectedReturnTrue() { + when(mLocalProfileManager.getA2dpProfile()).thenReturn(null); + + when(mHapProfile.setActiveDevice(null)).thenReturn(true); + assertThat(mPhoneMediaDevice.connect()).isTrue(); + } + + @Test + public void connect_hearingAidProfileAndA2dpProfileIsNull_isConnectedReturnFalse() { + when(mLocalProfileManager.getA2dpProfile()).thenReturn(null); + when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null); + + assertThat(mPhoneMediaDevice.connect()).isFalse(); + } + + @Test public void updateSummary_isActiveIsTrue_returnActiveString() { mPhoneMediaDevice.updateSummary(true); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java index c50d646c0861..ca1eefcad7de 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java @@ -29,6 +29,7 @@ import java.util.List; @Implements(value = UserManager.class) public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager { + private List<UserInfo> mUserInfos = addProfile(0, "Owner"); @Implementation protected static UserManager get(Context context) { @@ -37,16 +38,24 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager @Implementation protected int[] getProfileIdsWithDisabled(int userId) { - return new int[]{0}; + return mUserInfos.stream().mapToInt(s -> s.id).toArray(); } @Implementation protected List<UserInfo> getProfiles() { - UserInfo userInfo = new UserInfo(); - userInfo.id = 0; - List<UserInfo> userInfos = new ArrayList<>(); - userInfos.add(userInfo); - return userInfos; + return mUserInfos; + } + + public List<UserInfo> addProfile(int id, String name) { + List<UserInfo> userInfoList = mUserInfos; + if (userInfoList == null) { + userInfoList = new ArrayList<>(); + } + final UserInfo userInfo = new UserInfo(); + userInfo.id = id; + userInfo.name = name; + userInfoList.add(userInfo); + return userInfoList; } @Implementation diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index d639e5eca43d..f0399c569cbf 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -86,6 +86,7 @@ <uses-permission android:name="android.permission.DELETE_CACHE_FILES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" /> + <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" /> <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml index e1bf6cbd2198..5da7611a4462 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml @@ -17,15 +17,24 @@ */ --> -<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens --> -<com.android.keyguard.KeyguardMessageArea - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - style="@style/Keyguard.TextView" - android:id="@+id/keyguard_message_area" - android:singleLine="true" - android:ellipsize="marquee" - android:focusable="true" /> - +<!-- This contains error message field and padlock shared by pin/pattern/password screens --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" > + <FrameLayout + android:id="@+id/lock_icon_container" + android:layout_gravity="center" + android:layout_marginBottom="@dimen/keyguard_lock_padding" + android:layout_width="@dimen/keyguard_lock_width" + android:layout_height="@dimen/keyguard_lock_height" /> + <com.android.keyguard.KeyguardMessageArea + android:id="@+id/keyguard_message_area" + style="@style/Keyguard.TextView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:singleLine="true" + android:ellipsize="marquee" + android:focusable="true" /> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml index 38d2ecc3ddb5..91ca5c52c015 100644 --- a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml +++ b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml @@ -21,6 +21,6 @@ <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_top_margin) --> - <dimen name="keyguard_security_height">345dp</dimen> + <dimen name="keyguard_security_height">395dp</dimen> </resources> diff --git a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml index 90c4795d1e56..d7c9975ada41 100644 --- a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml +++ b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml @@ -21,5 +21,5 @@ <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_top_margin) --> - <dimen name="keyguard_security_height">400dp</dimen> + <dimen name="keyguard_security_height">450dp</dimen> </resources> diff --git a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml index 9ea04dc72ba9..a3c37e420f29 100644 --- a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml +++ b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml @@ -20,5 +20,5 @@ <resources> <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_top_margin) --> - <dimen name="keyguard_security_height">500dp</dimen> + <dimen name="keyguard_security_height">550dp</dimen> </resources> diff --git a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml index 9157822db960..1dc61c501beb 100644 --- a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml +++ b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml @@ -20,7 +20,7 @@ <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_top_margin) --> - <dimen name="keyguard_security_height">420dp</dimen> + <dimen name="keyguard_security_height">470dp</dimen> <dimen name="widget_big_font_size">100dp</dimen> </resources> diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index b6a41c19ec32..d67c98a337e8 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -27,11 +27,11 @@ <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_top_margin) --> - <dimen name="keyguard_security_height">400dp</dimen> + <dimen name="keyguard_security_height">450dp</dimen> <!-- Max Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_top_margin) --> - <dimen name="keyguard_security_max_height">455dp</dimen> + <dimen name="keyguard_security_max_height">505dp</dimen> <!-- Margin around the various security views --> <dimen name="keyguard_security_view_top_margin">8dp</dimen> diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml index 6c5c7fac3ed6..3d63b7d19c4f 100644 --- a/packages/SystemUI/res/layout/screen_record_dialog.xml +++ b/packages/SystemUI/res/layout/screen_record_dialog.xml @@ -5,26 +5,25 @@ android:clipChildren="false" android:clipToPadding="false" android:gravity="top" - android:orientation="vertical"> - - <Space - android:layout_width="match_parent" - android:layout_height="10dp"/> + android:orientation="vertical" + android:padding="@dimen/global_actions_padding" + android:background="@drawable/rounded_bg_full"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:background="@android:color/white"> + android:orientation="vertical"> <CheckBox android:id="@+id/checkbox_mic" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/screenrecord_mic_label"/> <CheckBox android:id="@+id/checkbox_taps" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/screenrecord_taps_label"/> <Button android:id="@+id/record_button" @@ -34,8 +33,4 @@ /> </LinearLayout> - <Space - android:layout_width="match_parent" - android:layout_height="10dp"/> - </LinearLayout> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 0fed96ee7ddf..27d2bcdc05b4 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -18,8 +18,6 @@ <declare-styleable name="KeyButtonView"> <!-- key code to send when pressed; if absent or 0, no key is sent --> <attr name="keyCode" format="integer" /> - <!-- does this button generate longpress / repeat events? --> - <attr name="keyRepeat" format="boolean" /> <!-- Should this button play sound effects, default true --> <attr name="playSound" format="boolean" /> <attr name="android:contentDescription" /> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index da433913bfa3..c6c2763f7801 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1069,10 +1069,10 @@ <string name="battery_saver_notification_action_text">Turn off Battery Saver</string> <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] --> - <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything on your screen including notifications, passwords, photos, messages and payment information.</string> + <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing the played audio and everything on your screen including notifications, passwords, photos, messages and payment information.</string> <!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] --> - <string name="media_projection_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> to record or cast your screen?</string> + <string name="media_projection_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> to record or cast your screen and played audio?</string> <!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] --> <string name="media_projection_remember_text">Don\'t show again</string> diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index e0ed111d9cb0..4a2731e5437a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -61,6 +61,7 @@ import com.android.systemui.statusbar.notification.NotificationInterruptionState import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.phone.StatusBarWindowController; +import com.android.systemui.statusbar.policy.ConfigurationController; import java.lang.annotation.Retention; @@ -74,7 +75,8 @@ import javax.inject.Singleton; * The controller manages addition, removal, and visible state of bubbles on screen. */ @Singleton -public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener { +public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener, + ConfigurationController.ConfigurationListener { private static final String TAG = "BubbleController"; @@ -84,6 +86,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED, DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION}) @interface DismissReason {} + static final int DISMISS_USER_GESTURE = 1; static final int DISMISS_AGED = 2; static final int DISMISS_TASK_FINISHED = 3; @@ -151,6 +154,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe public interface BubbleExpandListener { /** * Called when the expansion state of the bubble stack changes. + * * @param isExpanding whether it's expanding or collapsing * @param key the notification key associated with bubble being expanded */ @@ -179,13 +183,16 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe @Inject public BubbleController(Context context, StatusBarWindowController statusBarWindowController, - BubbleData data) { - this(context, statusBarWindowController, data, null /* synchronizer */); + BubbleData data, ConfigurationController configurationController) { + this(context, statusBarWindowController, data, null /* synchronizer */, + configurationController); } public BubbleController(Context context, StatusBarWindowController statusBarWindowController, - BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer) { + BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer, + ConfigurationController configurationController) { mContext = context; + configurationController.addCallback(this /* configurationListener */); mNotificationEntryManager = Dependency.get(NotificationEntryManager.class); mNotificationEntryManager.addNotificationEntryListener(mEntryListener); @@ -215,6 +222,20 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe mSurfaceSynchronizer = synchronizer; } + @Override + public void onUiModeChanged() { + if (mStackView != null) { + mStackView.onConfigChanged(); + } + } + + @Override + public void onOverlayChanged() { + if (mStackView != null) { + mStackView.onConfigChanged(); + } + } + /** * Set a listener to be notified when some states of the bubbles change. */ @@ -295,7 +316,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe /** * Adds or updates a bubble associated with the provided notification entry. * - * @param notif the notification associated with this bubble. + * @param notif the notification associated with this bubble. * @param updatePosition whether this update should promote the bubble to the top of the stack. */ public void updateBubble(NotificationEntry notif, boolean updatePosition) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 856b9d6c27e4..e8b346ed97ab 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -354,6 +354,13 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } } + /** + * Update bubble expanded view header when user toggles dark mode. + */ + void updateHeaderColor() { + mHeaderView.setBackgroundColor(mContext.getColor(R.attr.colorAccent)); + } + private void updateHeaderView() { mSettingsIcon.setContentDescription(getResources().getString( R.string.bubbles_settings_button_description, mAppName)); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 1cc6b8789872..461e79c671c4 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -238,6 +238,13 @@ public class BubbleStackView extends FrameLayout { mBubbleContainer.bringToFront(); } + /** + * Handle config changes. + */ + public void onConfigChanged() { + mExpandedBubble.expandedView.updateHeaderColor(); + } + @Override public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { getBoundsOnScreen(outRect); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index d06feedfd9aa..2db73065fe19 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -61,7 +61,9 @@ public class DozeService extends DreamService @Override public void onDestroy() { - mPluginManager.removePluginListener(this); + if (mPluginManager != null) { + mPluginManager.removePluginListener(this); + } super.onDestroy(); mDozeMachine = null; } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 7ed3a8065bc5..f07887ee6353 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1499,12 +1499,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final Context mContext; private final MyAdapter mAdapter; private MultiListLayout mGlobalActionsLayout; - private final Drawable mBackgroundDrawable; + private Drawable mBackgroundDrawable; private final ColorExtractor mColorExtractor; private final GlobalActionsPanelPlugin.PanelViewController mPanelController; private boolean mKeyguardShowing; private boolean mShowing; - private final float mScrimAlpha; + private float mScrimAlpha; ActionsDialog(Context context, MyAdapter adapter, GlobalActionsPanelPlugin.PanelViewController plugin) { @@ -1531,49 +1531,37 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); - - initializeLayout(); - setTitle(R.string.global_actions); mPanelController = plugin; - View panelView = initializePanel(); + initializeLayout(); + } + + private boolean initializePanel() { + if (!isPanelEnabled(mContext) || mPanelController == null) { + return false; + } + View panelView = mPanelController.getPanelContent(); if (panelView == null) { - mBackgroundDrawable = new GradientDrawable(context); - mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA; - } else { - mBackgroundDrawable = context.getDrawable( - com.android.systemui.R.drawable.global_action_panel_scrim); - mScrimAlpha = 1f; - addContentView( - panelView, - new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - } - window.setBackgroundDrawable(mBackgroundDrawable); - } - - private View initializePanel() { - if (isPanelEnabled(mContext) && mPanelController != null) { - View panelView = mPanelController.getPanelContent(); - if (panelView != null) { - FrameLayout panelContainer = new FrameLayout(mContext); - FrameLayout.LayoutParams panelParams = - new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.WRAP_CONTENT); - panelContainer.addView(panelView, panelParams); - return panelContainer; - } + return false; } - return null; + FrameLayout panelContainer = new FrameLayout(mContext); + FrameLayout.LayoutParams panelParams = + new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT); + panelContainer.addView(panelView, panelParams); + addContentView( + panelContainer, + new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + return true; } private void initializeLayout() { setContentView(getGlobalActionsLayoutId(mContext)); - mGlobalActionsLayout = (MultiListLayout) - findViewById(com.android.systemui.R.id.global_actions_view); + mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view); mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss()); mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() { @Override @@ -1586,8 +1574,18 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, }); mGlobalActionsLayout.setRotationListener(this::onRotate); mGlobalActionsLayout.setAdapter(mAdapter); - mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext) - && mPanelController != null); + + boolean panelEnabled = initializePanel(); + if (!panelEnabled) { + mBackgroundDrawable = new GradientDrawable(mContext); + mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA; + } else { + mBackgroundDrawable = mContext.getDrawable( + com.android.systemui.R.drawable.global_action_panel_scrim); + mScrimAlpha = 1f; + } + mGlobalActionsLayout.setSnapToEdge(panelEnabled); + getWindow().setBackgroundDrawable(mBackgroundDrawable); } private int getGlobalActionsLayoutId(Context context) { @@ -1743,7 +1741,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, */ private static boolean isPanelEnabled(Context context) { return FeatureFlagUtils.isEnabled( - context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED); } + context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED); + } /** * Determines whether the Global Actions menu should use a separated view for emergency actions. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 295abcbcfd17..2f99cf311eec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -596,7 +596,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void appTransitionCancelled(int displayId) { synchronized (mLock) { - mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId).sendToTarget(); + mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId, 0 /* unused */) + .sendToTarget(); } } @@ -624,7 +625,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void appTransitionFinished(int displayId) { synchronized (mLock) { - mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId).sendToTarget(); + mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId, 0 /* unused */) + .sendToTarget(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java index 0a395499347d..2da68249d8c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java @@ -492,13 +492,10 @@ public class KeyguardAffordanceView extends ImageView { int currentAlpha = getImageAlpha(); ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha); mAlphaAnimator = animator; - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int alpha = (int) animation.getAnimatedValue(); - if (background != null) background.mutate().setAlpha(alpha); - setImageAlpha(alpha); - } + animator.addUpdateListener(animation -> { + int alpha1 = (int) animation.getAnimatedValue(); + if (background != null) background.mutate().setAlpha(alpha1); + setImageAlpha(alpha1); }); animator.addListener(mAlphaEndListener); if (interpolator == null) { @@ -520,6 +517,10 @@ public class KeyguardAffordanceView extends ImageView { } } + public boolean isAnimatingAlpha() { + return mAlphaAnimator != null; + } + private Animator.AnimatorListener getEndListener(final Runnable runnable) { return new AnimatorListenerAdapter() { boolean mCancelled; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index 14dc272d1c5e..2bb6e3e32dc7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -32,6 +32,7 @@ import android.view.IWindowManager; import android.view.View; import android.view.WindowManagerGlobal; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.statusbar.CommandQueue.Callbacks; @@ -58,7 +59,8 @@ public class NavigationBarController implements Callbacks { private final DisplayManager mDisplayManager; /** A displayId - nav bar maps. */ - private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>(); + @VisibleForTesting + SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>(); @Inject public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) { @@ -101,7 +103,8 @@ public class NavigationBarController implements Callbacks { * * @param display the display to add navigation bar on. */ - private void createNavigationBar(Display display) { + @VisibleForTesting + void createNavigationBar(Display display) { if (display == null) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index 2bbc53c05cbe..fdf8ccee3f62 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -28,6 +28,7 @@ import android.view.IWindowManager; import android.view.MotionEvent; import android.view.View; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.statusbar.CommandQueue; @@ -48,8 +49,10 @@ public class AutoHideController implements CommandQueue.Callbacks { private StatusBar mStatusBar; private NavigationBarFragment mNavigationBar; - private int mDisplayId; - private int mSystemUiVisibility; + @VisibleForTesting + int mDisplayId; + @VisibleForTesting + int mSystemUiVisibility; // last value sent to window manager private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE; @@ -123,7 +126,8 @@ public class AutoHideController implements CommandQueue.Callbacks { } } - private void notifySystemUiVisibilityChanged(int vis) { + @VisibleForTesting + void notifySystemUiVisibilityChanged(int vis) { try { if (mLastDispatchedSystemUiVisibility != vis) { mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis); @@ -213,11 +217,12 @@ public class AutoHideController implements CommandQueue.Callbacks { return mask; } - private boolean hasNavigationBar() { + boolean hasNavigationBar() { return mNavigationBar != null; } - private boolean hasStatusBar() { + @VisibleForTesting + boolean hasStatusBar() { return mStatusBar != null; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 6fe23fbbbf86..847f3ff9f24d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -831,6 +831,15 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } + /** + * Sets the alpha of the indication areas and affordances, excluding the lock icon. + */ + public void setAffordanceAlpha(float alpha) { + mLeftAffordanceView.setAlpha(alpha); + mRightAffordanceView.setAlpha(alpha); + mIndicationArea.setAlpha(alpha); + } + private class DefaultLeftButton implements IntentButton { private IconState mIconState = new IconState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 7d1367971ed6..19373ac8e28b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -88,6 +88,7 @@ public class KeyguardBouncer { private int mBouncerPromptReason; private boolean mIsAnimatingAway; private boolean mIsScrimmed; + private ViewGroup mLockIconContainer; public KeyguardBouncer(Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils, ViewGroup container, @@ -171,6 +172,10 @@ public class KeyguardBouncer { return isShowing() && mIsScrimmed; } + public ViewGroup getLockIconContainer() { + return mRoot == null || mRoot.getVisibility() != View.VISIBLE ? null : mLockIconContainer; + } + /** * This method must be called at the end of the bouncer animation when * the translation is performed manually by the user, otherwise FalsingManager @@ -401,6 +406,7 @@ public class KeyguardBouncer { removeView(); mHandler.removeCallbacks(mRemoveViewRunnable); mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null); + mLockIconContainer = mRoot.findViewById(R.id.lock_icon_container); mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view); mKeyguardView.setLockPatternUtils(mLockPatternUtils); mKeyguardView.setViewMediatorCallback(mCallback); @@ -420,6 +426,7 @@ public class KeyguardBouncer { if (mRoot != null && mRoot.getParent() == mContainer) { mContainer.removeView(mRoot); mRoot = null; + mLockIconContainer = null; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 09789019d6ef..ea30451175d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -159,7 +159,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private OverviewProxyService mOverviewProxyService; - private int mDisplayId; + @VisibleForTesting + public int mDisplayId; private boolean mIsOnDefaultDisplay; public boolean mHomeBlockedThisTouch; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index babee5393e8c..253bdfb1a206 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -192,7 +192,6 @@ public class NotificationPanelView extends PanelView implements protected int mQsMinExpansionHeight; protected int mQsMaxExpansionHeight; private int mQsPeekHeight; - private int mBouncerTop; private boolean mStackScrollerOverscrolling; private boolean mQsExpansionFromOverscroll; private float mLastOverscroll; @@ -325,6 +324,7 @@ public class NotificationPanelView extends PanelView implements private final ShadeController mShadeController = Dependency.get(ShadeController.class); private int mDisplayId; + private KeyguardBouncer mBouncer; /** * Cache the resource id of the theme to avoid unnecessary work in onThemeChanged. @@ -690,11 +690,6 @@ public class NotificationPanelView extends PanelView implements return count; } - public void setBouncerTop(int bouncerTop) { - mBouncerTop = bouncerTop; - positionClockAndNotifications(); - } - private void updateClock() { if (!mKeyguardStatusViewAnimating) { mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha); @@ -1741,7 +1736,6 @@ public class NotificationPanelView extends PanelView implements } updateExpandedHeight(expandedHeight); updateHeader(); - updateUnlockIcon(); updateNotificationTranslucency(); updatePanelExpanded(); if (DEBUG) { @@ -1834,19 +1828,6 @@ public class NotificationPanelView extends PanelView implements return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */); } - private void updateUnlockIcon() { - if (mBarState == StatusBarState.KEYGUARD - || mBarState == StatusBarState.SHADE_LOCKED) { - boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance; - KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon(); - if (active != mUnlockIconActive && mTracking) { - lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true, 150, - Interpolators.FAST_OUT_LINEAR_IN, null); - } - mUnlockIconActive = active; - } - } - /** * Hides the header when notifications are colliding with it. */ @@ -1913,7 +1894,7 @@ public class NotificationPanelView extends PanelView implements ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f, getExpandedFraction()); float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction()); - mKeyguardBottomArea.setAlpha(alpha); + mKeyguardBottomArea.setAffordanceAlpha(alpha); mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS : IMPORTANT_FOR_ACCESSIBILITY_AUTO); @@ -2061,11 +2042,6 @@ public class NotificationPanelView extends PanelView implements mAffordanceHelper.reset(true); } } - if (!expand && (mBarState == StatusBarState.KEYGUARD - || mBarState == StatusBarState.SHADE_LOCKED)) { - KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon(); - lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null); - } } @Override @@ -2215,22 +2191,6 @@ public class NotificationPanelView extends PanelView implements return; } super.startUnlockHintAnimation(); - startHighlightIconAnimation(getCenterIcon()); - } - - /** - * Starts the highlight (making it fully opaque) animation on an icon. - */ - private void startHighlightIconAnimation(final KeyguardAffordanceView icon) { - icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION, - Interpolators.FAST_OUT_SLOW_IN, new Runnable() { - @Override - public void run() { - icon.setImageAlpha(icon.getRestingAlpha(), - true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION, - Interpolators.FAST_OUT_SLOW_IN, null); - } - }); } @Override @@ -2969,6 +2929,7 @@ public class NotificationPanelView extends PanelView implements public void onBouncerPreHideAnimation() { setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */, false /* goingToFullShade */); + updateLockIcon(); } @Override @@ -3058,4 +3019,54 @@ public class NotificationPanelView extends PanelView implements public void showTransientIndication(int id) { mKeyguardBottomArea.showTransientIndication(id); } + + /** + * Sets the reference to the {@link KeyguardBouncer}. + */ + public void setBouncer(KeyguardBouncer bouncer) { + mBouncer = bouncer; + updateLockIcon(); + } + + public void updateLockIcon() { + if (mBouncer == null) { + return; + } + + ViewGroup bouncerContainer = mBouncer.getLockIconContainer(); + LockIcon lockIcon = mKeyguardBottomArea.getLockIcon(); + + if (mBouncer.isAnimatingAway()) { + if (!lockIcon.isAnimatingAlpha() && lockIcon.getAlpha() != 0) { + lockIcon.setImageAlpha(0, true /* animate */); + } + // Let's not re-apply the translation if the bouncer is animating, its + // animation also includes translation and transition would be jarring. + return; + } + + float translation = 0; + if (bouncerContainer != null) { + float bottomAreaContainerY = getCommonTop(lockIcon); + float bouncerLockY = getCommonTop(bouncerContainer); + if (bouncerLockY < bottomAreaContainerY) { + translation = bouncerLockY - bottomAreaContainerY; + } + } + lockIcon.setTranslationY(translation); + + if (lockIcon.getAlpha() != 1) { + lockIcon.setImageAlpha(1, false /* animate */); + } + } + + private static float getCommonTop(View view) { + float y = view.getTop(); + ViewGroup parent = (ViewGroup) view.getParent(); + while (!(parent instanceof StatusBarWindowView)) { + y += parent.getY(); + parent = (ViewGroup) parent.getParent(); + } + return y; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 2495d2253abb..99345d26abc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -1115,6 +1115,7 @@ public abstract class PanelView extends FrameLayout { View[] viewsToAnimate = { mKeyguardBottomArea.getIndicationArea(), + mKeyguardBottomArea.getLockIcon(), mStatusBar.getAmbientIndicationContainer()}; for (View v : viewsToAnimate) { if (v == null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 8db08221ef73..c4b41d458893 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -122,6 +122,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; @@ -215,7 +216,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardMonitor; -import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -533,8 +533,7 @@ public class StatusBar extends SystemUI implements DemoMode, private KeyguardUserSwitcher mKeyguardUserSwitcher; protected UserSwitcherController mUserSwitcherController; private NetworkController mNetworkController; - private KeyguardMonitorImpl mKeyguardMonitor - = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class); + private KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); private BatteryController mBatteryController; protected boolean mPanelExpanded; private UiModeManager mUiModeManager; @@ -882,7 +881,6 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanel.getLockIcon()); mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController); - mAmbientIndicationContainer = mStatusBarWindow.findViewById( R.id.ambient_indication_container); @@ -1058,8 +1056,21 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationShelf.setOnActivatedListener(mPresenter); mRemoteInputManager.getController().addCallback(mStatusBarWindowController); - mNotificationActivityStarter = new StatusBarNotificationActivityStarter( - mContext, mNotificationPanel, mPresenter, mHeadsUpManager, mActivityLaunchAnimator); + final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback = + (StatusBarRemoteInputCallback) Dependency.get( + NotificationRemoteInputManager.Callback.class); + final ShadeController shadeController = Dependency.get(ShadeController.class); + final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class); + + mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext, + mCommandQueue, mAssistManager, mNotificationPanel, mPresenter, mEntryManager, + mHeadsUpManager, activityStarter, mActivityLaunchAnimator, + mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager, + mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager, + mLockscreenUserManager, shadeController, mKeyguardMonitor, + mNotificationInterruptionStateProvider, mMetricsLogger, + new LockPatternUtils(mContext)); + mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); mEntryManager.setRowBinder(rowBinder); @@ -1220,6 +1231,7 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); mLightBarController.setBiometricUnlockController(mBiometricUnlockController); mMediaManager.setBiometricUnlockController(mBiometricUnlockController); + mNotificationPanel.setBouncer(mStatusBarKeyguardViewManager.getBouncer()); Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked); Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 5014783c43b1..e8a5c7a5c14a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -166,16 +166,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry, mExpansionCallback); - mContainer.addOnLayoutChangeListener(this::onContainerLayout); mNotificationPanelView = notificationPanelView; notificationPanelView.setExpansionListener(this::onPanelExpansionChanged); } - private void onContainerLayout(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - mNotificationPanelView.setBouncerTop(mBouncer.getTop()); - } - @VisibleForTesting void onPanelExpansionChanged(float expansion, boolean tracking) { // We don't want to translate the bounce when: @@ -198,6 +192,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */); } } + mNotificationPanelView.updateLockIcon(); } /** @@ -795,6 +790,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb setDozing(isDozing); } + public KeyguardBouncer getBouncer() { + return mBouncer; + } + private static class DismissWithActionRequest { final OnDismissAction dismissAction; final Runnable cancelAction; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 74c00187bd07..7e45507b4985 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.Dependency.MAIN_HANDLER; -import static com.android.systemui.SysUiServiceProvider.getComponent; import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions; import android.app.ActivityManager; @@ -32,9 +31,7 @@ import android.content.Intent; import android.os.AsyncTask; import android.os.Looper; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; -import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.service.notification.StatusBarNotification; import android.text.TextUtils; @@ -78,27 +75,18 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private static final String TAG = "NotificationClickHandler"; protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private final AssistManager mAssistManager = Dependency.get(AssistManager.class); - private final NotificationGroupManager mGroupManager = - Dependency.get(NotificationGroupManager.class); - private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback = - (StatusBarRemoteInputCallback) Dependency.get( - NotificationRemoteInputManager.Callback.class); - private final NotificationRemoteInputManager mRemoteInputManager = - Dependency.get(NotificationRemoteInputManager.class); - private final NotificationLockscreenUserManager mLockscreenUserManager = - Dependency.get(NotificationLockscreenUserManager.class); - private final ShadeController mShadeController = Dependency.get(ShadeController.class); - private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); - private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); - private final NotificationEntryManager mEntryManager = - Dependency.get(NotificationEntryManager.class); - private final StatusBarStateController mStatusBarStateController = - Dependency.get(StatusBarStateController.class); - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider = - Dependency.get(NotificationInterruptionStateProvider.class); - private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); - + private final AssistManager mAssistManager; + private final NotificationGroupManager mGroupManager; + private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback; + private final NotificationRemoteInputManager mRemoteInputManager; + private final NotificationLockscreenUserManager mLockscreenUserManager; + private final ShadeController mShadeController; + private final KeyguardMonitor mKeyguardMonitor; + private final ActivityStarter mActivityStarter; + private final NotificationEntryManager mEntryManager; + private final StatusBarStateController mStatusBarStateController; + private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private final MetricsLogger mMetricsLogger; private final Context mContext; private final NotificationPanelView mNotificationPanel; private final NotificationPresenter mPresenter; @@ -113,29 +101,55 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private boolean mIsCollapsingToShowActivityOverLockscreen; public StatusBarNotificationActivityStarter(Context context, + CommandQueue commandQueue, + AssistManager assistManager, NotificationPanelView panel, NotificationPresenter presenter, + NotificationEntryManager entryManager, HeadsUpManagerPhone headsUpManager, - ActivityLaunchAnimator activityLaunchAnimator) { + ActivityStarter activityStarter, + ActivityLaunchAnimator activityLaunchAnimator, + IStatusBarService statusBarService, + StatusBarStateController statusBarStateController, + KeyguardManager keyguardManager, + IDreamManager dreamManager, + NotificationRemoteInputManager remoteInputManager, + StatusBarRemoteInputCallback remoteInputCallback, + NotificationGroupManager groupManager, + NotificationLockscreenUserManager lockscreenUserManager, + ShadeController shadeController, + KeyguardMonitor keyguardMonitor, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + MetricsLogger metricsLogger, + LockPatternUtils lockPatternUtils) { mContext = context; mNotificationPanel = panel; mPresenter = presenter; - mLockPatternUtils = new LockPatternUtils(context); mHeadsUpManager = headsUpManager; - mKeyguardManager = context.getSystemService(KeyguardManager.class); mActivityLaunchAnimator = activityLaunchAnimator; - mBarService = IStatusBarService.Stub.asInterface( - ServiceManager.getService(Context.STATUS_BAR_SERVICE)); - mCommandQueue = getComponent(context, CommandQueue.class); - mDreamManager = IDreamManager.Stub.asInterface( - ServiceManager.checkService(DreamService.DREAM_SERVICE)); - + mBarService = statusBarService; + mCommandQueue = commandQueue; + mKeyguardManager = keyguardManager; + mDreamManager = dreamManager; + mRemoteInputManager = remoteInputManager; + mLockscreenUserManager = lockscreenUserManager; + mShadeController = shadeController; + mKeyguardMonitor = keyguardMonitor; + mActivityStarter = activityStarter; + mEntryManager = entryManager; + mStatusBarStateController = statusBarStateController; + mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mMetricsLogger = metricsLogger; + mAssistManager = assistManager; + mGroupManager = groupManager; + mLockPatternUtils = lockPatternUtils; mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onPendingEntryAdded(NotificationEntry entry) { handleFullScreenIntent(entry); } }); + mStatusBarRemoteInputCallback = remoteInputCallback; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 024404d2175b..1e059835f086 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -66,7 +66,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private int mTouchDownX; private int mTouchDownY; private boolean mIsVertical; - private boolean mSupportsLongpress = true; private AudioManager mAudioManager; private boolean mGestureAborted; private boolean mLongClicked; @@ -83,7 +82,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { // Just an old-fashioned ImageView performLongClick(); mLongClicked = true; - } else if (mSupportsLongpress) { + } else { sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); mLongClicked = true; @@ -104,7 +103,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, KEYCODE_UNKNOWN); - mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true); mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true); TypedValue value = new TypedValue(); @@ -166,7 +164,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { super.onInitializeAccessibilityNodeInfo(info); if (mCode != KEYCODE_UNKNOWN) { info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null)); - if (mSupportsLongpress || isLongClickable()) { + if (isLongClickable()) { info.addAction( new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java index aba23778f08c..01498e6bd54d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -29,6 +29,25 @@ public interface KeyguardMonitor extends CallbackController<Callback> { long getKeyguardFadingAwayDelay(); long calculateGoingToFullShadeDelay(); + default boolean isDeviceInteractive() { + return false; + } + + default void setLaunchTransitionFadingAway(boolean b) { + } + + default void notifyKeyguardGoingAway(boolean b) { + } + + default void notifyKeyguardFadingAway(long delay, long fadeoutDuration) { + } + + default void notifyKeyguardDoneFading() { + } + + default void notifyKeyguardState(boolean showing, boolean methodSecure, boolean occluded) { + } + interface Callback { void onKeyguardShowingChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index d3164a09f7e6..c8f389e4ccbe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -474,8 +474,8 @@ public class MobileSignalController extends SignalController< private MobileIconGroup getNr5GIconGroup() { if (mServiceState == null) return null; - int nrStatus = mServiceState.getNrStatus(); - if (nrStatus == NetworkRegistrationInfo.NR_STATUS_CONNECTED) { + int nrState = mServiceState.getNrState(); + if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) { // Check if the NR 5G is using millimeter wave and the icon is config. if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) { if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) { @@ -488,11 +488,11 @@ public class MobileSignalController extends SignalController< if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) { return mConfig.nr5GIconMap.get(Config.NR_CONNECTED); } - } else if (nrStatus == NetworkRegistrationInfo.NR_STATUS_NOT_RESTRICTED) { + } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) { if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) { return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED); } - } else if (nrStatus == NetworkRegistrationInfo.NR_STATUS_RESTRICTED) { + } else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) { if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) { return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 4e9d892dd809..63b66732c02e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -44,6 +44,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.StatusBarWindowController; +import com.android.systemui.statusbar.policy.ConfigurationController; import org.junit.Before; import org.junit.Test; @@ -66,6 +67,9 @@ public class BubbleControllerTest extends SysuiTestCase { private IActivityManager mActivityManager; @Mock private DozeParameters mDozeParameters; + @Mock + private ConfigurationController mConfigurationController; + private FrameLayout mStatusBarView; @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor; @@ -97,6 +101,7 @@ public class BubbleControllerTest extends SysuiTestCase { mStatusBarView = new FrameLayout(mContext); mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager); + // Bubbles get added to status bar window view mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters); @@ -115,7 +120,7 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleData = new BubbleData(); mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController, - mBubbleData); + mBubbleData, mConfigurationController); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -331,8 +336,9 @@ public class BubbleControllerTest extends SysuiTestCase { static class TestableBubbleController extends BubbleController { // Let's assume surfaces can be synchronized immediately. TestableBubbleController(Context context, - StatusBarWindowController statusBarWindowController, BubbleData data) { - super(context, statusBarWindowController, data, Runnable::run); + StatusBarWindowController statusBarWindowController, BubbleData data, + ConfigurationController configurationController) { + super(context, statusBarWindowController, data, Runnable::run, configurationController); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index dd2636803b94..c2f55e2f9b99 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -41,6 +41,7 @@ public class CommandQueueTest extends SysuiTestCase { private CommandQueue mCommandQueue; private Callbacks mCallbacks; + private static final int SECONDARY_DISPLAY = 1; @Before public void setup() { @@ -68,7 +69,6 @@ public class CommandQueueTest extends SysuiTestCase { verify(mCallbacks).removeIcon(eq(slot)); } - // TODO(b/117478341): add test case for multi-display @Test public void testDisable() { int state1 = 14; @@ -79,6 +79,15 @@ public class CommandQueueTest extends SysuiTestCase { } @Test + public void testDisableForSecondaryDisplay() { + int state1 = 14; + int state2 = 42; + mCommandQueue.disable(SECONDARY_DISPLAY, state1, state2); + waitForIdleSync(); + verify(mCallbacks).disable(eq(SECONDARY_DISPLAY), eq(state1), eq(state2), eq(true)); + } + + @Test public void testExpandNotifications() { mCommandQueue.animateExpandNotificationsPanel(); waitForIdleSync(); @@ -100,7 +109,6 @@ public class CommandQueueTest extends SysuiTestCase { verify(mCallbacks).animateExpandSettingsPanel(eq(panel)); } - // TODO(b/117478341): add test case for multi-display @Test public void testSetSystemUiVisibility() { Rect r = new Rect(); @@ -110,7 +118,15 @@ public class CommandQueueTest extends SysuiTestCase { eq(null), eq(r)); } - // TODO(b/117478341): add test case for multi-display + @Test + public void testSetSystemUiVisibilityForSecondaryDisplay() { + Rect r = new Rect(); + mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r); + waitForIdleSync(); + verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4), + eq(null), eq(r)); + } + @Test public void testTopAppWindowChanged() { mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true); @@ -118,7 +134,13 @@ public class CommandQueueTest extends SysuiTestCase { verify(mCallbacks).topAppWindowChanged(eq(DEFAULT_DISPLAY), eq(true)); } - // TODO(b/117478341): add test case for multi-display + @Test + public void testTopAppWindowChangedForSecondaryDisplay() { + mCommandQueue.topAppWindowChanged(SECONDARY_DISPLAY, true); + waitForIdleSync(); + verify(mCallbacks).topAppWindowChanged(eq(SECONDARY_DISPLAY), eq(true)); + } + @Test public void testShowImeButton() { mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true); @@ -128,6 +150,14 @@ public class CommandQueueTest extends SysuiTestCase { } @Test + public void testShowImeButtonForSecondaryDisplay() { + mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true); + waitForIdleSync(); + verify(mCallbacks).setImeWindowStatus( + eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true)); + } + + @Test public void testShowRecentApps() { mCommandQueue.showRecentApps(true); waitForIdleSync(); @@ -176,7 +206,6 @@ public class CommandQueueTest extends SysuiTestCase { verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1)); } - // TODO(b/117478341): add test case for multi-display @Test public void testSetWindowState() { mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2); @@ -185,13 +214,19 @@ public class CommandQueueTest extends SysuiTestCase { } @Test + public void testSetWindowStateForSecondaryDisplay() { + mCommandQueue.setWindowState(SECONDARY_DISPLAY, 1, 2); + waitForIdleSync(); + verify(mCallbacks).setWindowState(eq(SECONDARY_DISPLAY), eq(1), eq(2)); + } + + @Test public void testScreenPinRequest() { mCommandQueue.showScreenPinningRequest(1); waitForIdleSync(); verify(mCallbacks).showScreenPinningRequest(eq(1)); } - // TODO(b/117478341): add test case for multi-display @Test public void testAppTransitionPending() { mCommandQueue.appTransitionPending(DEFAULT_DISPLAY); @@ -199,7 +234,13 @@ public class CommandQueueTest extends SysuiTestCase { verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false)); } - // TODO(b/117478341): add test case for multi-display + @Test + public void testAppTransitionPendingForSecondaryDisplay() { + mCommandQueue.appTransitionPending(SECONDARY_DISPLAY); + waitForIdleSync(); + verify(mCallbacks).appTransitionPending(eq(SECONDARY_DISPLAY), eq(false)); + } + @Test public void testAppTransitionCancelled() { mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY); @@ -207,7 +248,13 @@ public class CommandQueueTest extends SysuiTestCase { verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY)); } - // TODO(b/117478341): add test case for multi-display + @Test + public void testAppTransitionCancelledForSecondaryDisplay() { + mCommandQueue.appTransitionCancelled(SECONDARY_DISPLAY); + waitForIdleSync(); + verify(mCallbacks).appTransitionCancelled(eq(SECONDARY_DISPLAY)); + } + @Test public void testAppTransitionStarting() { mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2); @@ -216,7 +263,14 @@ public class CommandQueueTest extends SysuiTestCase { eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false)); } - // TODO(b/117478341): add test case for multi-display + @Test + public void testAppTransitionStartingForSecondaryDisplay() { + mCommandQueue.appTransitionStarting(SECONDARY_DISPLAY, 1, 2); + waitForIdleSync(); + verify(mCallbacks).appTransitionStarting( + eq(SECONDARY_DISPLAY), eq(1L), eq(2L), eq(false)); + } + @Test public void testAppTransitionFinished() { mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY); @@ -225,6 +279,13 @@ public class CommandQueueTest extends SysuiTestCase { } @Test + public void testAppTransitionFinishedForSecondaryDisplay() { + mCommandQueue.appTransitionFinished(SECONDARY_DISPLAY); + waitForIdleSync(); + verify(mCallbacks).appTransitionFinished(eq(SECONDARY_DISPLAY)); + } + + @Test public void testAssistDisclosure() { mCommandQueue.showAssistDisclosure(); waitForIdleSync(); @@ -290,4 +351,25 @@ public class CommandQueueTest extends SysuiTestCase { waitForIdleSync(); verify(mCallbacks).handleSystemKey(eq(1)); } + + @Test + public void testOnDisplayReady() { + mCommandQueue.onDisplayReady(DEFAULT_DISPLAY); + waitForIdleSync(); + verify(mCallbacks).onDisplayReady(eq(DEFAULT_DISPLAY)); + } + + @Test + public void testOnDisplayReadyForSecondaryDisplay() { + mCommandQueue.onDisplayReady(SECONDARY_DISPLAY); + waitForIdleSync(); + verify(mCallbacks).onDisplayReady(eq(SECONDARY_DISPLAY)); + } + + @Test + public void testOnDisplayRemoved() { + mCommandQueue.onDisplayRemoved(SECONDARY_DISPLAY); + waitForIdleSync(); + verify(mCallbacks).onDisplayRemoved(eq(SECONDARY_DISPLAY)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java new file mode 100644 index 000000000000..34a726d526a3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java @@ -0,0 +1,243 @@ +/* + * 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.statusbar; + +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.hardware.display.DisplayManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.util.SparseArray; +import android.view.Display; +import android.view.WindowManager; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.Dependency; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.phone.NavigationBarFragment; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** atest NavigationBarControllerTest */ +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class NavigationBarControllerTest extends SysuiTestCase { + + private NavigationBarController mNavigationBarController; + private Display mDisplay; + private NavigationBarFragment mDefaultNavBar; + private NavigationBarFragment mSecondaryNavBar; + + private static final int SECONDARY_DISPLAY = 1; + + @Before + public void setUp() { + mContext.putComponent(CommandQueue.class, mock(CommandQueue.class)); + mNavigationBarController = spy( + new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER))); + initializeNavigationBars(); + } + + private void initializeNavigationBars() { + mNavigationBarController.mNavigationBars = mock(SparseArray.class); + mDefaultNavBar = mock(NavigationBarFragment.class); + mDefaultNavBar.mDisplayId = DEFAULT_DISPLAY; + doReturn(mDefaultNavBar) + .when(mNavigationBarController.mNavigationBars).get(DEFAULT_DISPLAY); + + mSecondaryNavBar = mock(NavigationBarFragment.class); + mSecondaryNavBar.mDisplayId = SECONDARY_DISPLAY; + doReturn(mSecondaryNavBar) + .when(mNavigationBarController.mNavigationBars).get(SECONDARY_DISPLAY); + } + + @After + public void tearDown() { + mNavigationBarController = null; + mDisplay = null; + mDefaultNavBar = null; + mSecondaryNavBar = null; + } + + @Test + public void testCreateNavigationBarsIncludeDefaultTrue() { + initializeDisplayManager(); + doNothing().when(mNavigationBarController).createNavigationBar(any()); + + mNavigationBarController.createNavigationBars(true); + + verify(mNavigationBarController).createNavigationBar(any(Display.class)); + } + + @Test + public void testCreateNavigationBarsIncludeDefaultFalse() { + initializeDisplayManager(); + doNothing().when(mNavigationBarController).createNavigationBar(any()); + + mNavigationBarController.createNavigationBars(false); + + verify(mNavigationBarController, never()).createNavigationBar(any()); + } + + private void initializeDisplayManager() { + DisplayManager displayManager = mock(DisplayManager.class); + mDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay(); + Display[] displays = {mDisplay}; + when(displayManager.getDisplays()).thenReturn(displays); + mContext.addMockSystemService(Context.DISPLAY_SERVICE, displayManager); + } + + // Tests if NPE occurs when call checkNavBarModes() with invalid display. + @Test + public void testCheckNavBarModesWithInvalidDisplay() { + mNavigationBarController.checkNavBarModes(INVALID_DISPLAY); + } + + @Test + public void testCheckNavBarModesWithDefaultDisplay() { + doNothing().when(mDefaultNavBar).checkNavBarModes(); + + mNavigationBarController.checkNavBarModes(DEFAULT_DISPLAY); + + verify(mDefaultNavBar).checkNavBarModes(); + } + + @Test + public void testCheckNavBarModesWithSecondaryDisplay() { + doNothing().when(mSecondaryNavBar).checkNavBarModes(); + + mNavigationBarController.checkNavBarModes(SECONDARY_DISPLAY); + + verify(mSecondaryNavBar).checkNavBarModes(); + } + + // Tests if NPE occurs when call finishBarAnimations() with invalid display. + @Test + public void testFinishBarAnimationsWithInvalidDisplay() { + mNavigationBarController.finishBarAnimations(INVALID_DISPLAY); + } + + @Test + public void testFinishBarAnimationsWithDefaultDisplay() { + doNothing().when(mDefaultNavBar).finishBarAnimations(); + + mNavigationBarController.finishBarAnimations(DEFAULT_DISPLAY); + + verify(mDefaultNavBar).finishBarAnimations(); + } + + @Test + public void testFinishBarAnimationsWithSecondaryDisplay() { + doNothing().when(mSecondaryNavBar).finishBarAnimations(); + + mNavigationBarController.finishBarAnimations(SECONDARY_DISPLAY); + + verify(mSecondaryNavBar).finishBarAnimations(); + } + + // Tests if NPE occurs when call touchAutoDim() with invalid display. + @Test + public void testTouchAutoDimWithInvalidDisplay() { + mNavigationBarController.touchAutoDim(INVALID_DISPLAY); + } + + @Test + public void testTouchAutoDimWithDefaultDisplay() { + doNothing().when(mDefaultNavBar).touchAutoDim(); + + mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY); + + verify(mDefaultNavBar).touchAutoDim(); + } + + @Test + public void testTouchAutoDimWithSecondaryDisplay() { + doNothing().when(mSecondaryNavBar).touchAutoDim(); + + mNavigationBarController.touchAutoDim(SECONDARY_DISPLAY); + + verify(mSecondaryNavBar).touchAutoDim(); + } + + // Tests if NPE occurs when call transitionTo() with invalid display. + @Test + public void testTransitionToWithInvalidDisplay() { + mNavigationBarController.transitionTo(INVALID_DISPLAY, 3, true); + } + + @Test + public void testTransitionToWithDefaultDisplay() { + doNothing().when(mDefaultNavBar).transitionTo(anyInt(), anyBoolean()); + + mNavigationBarController.transitionTo(DEFAULT_DISPLAY, 3, true); + + verify(mDefaultNavBar).transitionTo(eq(3), eq(true)); + } + + @Test + public void testTransitionToWithSecondaryDisplay() { + doNothing().when(mSecondaryNavBar).transitionTo(anyInt(), anyBoolean()); + + mNavigationBarController.transitionTo(SECONDARY_DISPLAY, 3, true); + + verify(mSecondaryNavBar).transitionTo(eq(3), eq(true)); + } + + // Tests if NPE occurs when call disableAnimationsDuringHide() with invalid display. + @Test + public void testDisableAnimationsDuringHideWithInvalidDisplay() { + mNavigationBarController.disableAnimationsDuringHide(INVALID_DISPLAY, 500L); + } + + @Test + public void testDisableAnimationsDuringHideWithDefaultDisplay() { + doNothing().when(mDefaultNavBar).disableAnimationsDuringHide(anyLong()); + + mNavigationBarController.disableAnimationsDuringHide(DEFAULT_DISPLAY, 500L); + + verify(mDefaultNavBar).disableAnimationsDuringHide(eq(500L)); + } + + @Test + public void testDisableAnimationsDuringHideWithSecondaryDisplay() { + doNothing().when(mSecondaryNavBar).disableAnimationsDuringHide(anyLong()); + + mNavigationBarController.disableAnimationsDuringHide(SECONDARY_DISPLAY, 500L); + + verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java new file mode 100644 index 000000000000..1b34a7584994 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java @@ -0,0 +1,118 @@ +/* + * 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.statusbar.phone; + +import static android.view.Display.DEFAULT_DISPLAY; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +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.verify; + +import android.graphics.Rect; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.Dependency; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.CommandQueue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** atest AutoHideControllerTest */ +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class AutoHideControllerTest extends SysuiTestCase { + + private AutoHideController mAutoHideController; + + private static final int FULL_MASK = 0xffffffff; + + @Before + public void setUp() { + mContext.putComponent(CommandQueue.class, mock(CommandQueue.class)); + mAutoHideController = + spy(new AutoHideController(mContext, Dependency.get(Dependency.MAIN_HANDLER))); + mAutoHideController.mDisplayId = DEFAULT_DISPLAY; + mAutoHideController.mSystemUiVisibility = View.VISIBLE; + } + + @After + public void tearDown() { + mAutoHideController = null; + } + + @Test + public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() { + mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect()); + + verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt()); + } + + @Test + public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() { + mAutoHideController + .setSystemUiVisibility(DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect()); + + verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt()); + } + + // Test if status bar unhide status doesn't change without status bar. + @Test + public void testSetSystemUiVisibilityWithoutStatusBar() { + doReturn(false).when(mAutoHideController).hasStatusBar(); + int expectedStatus = View.STATUS_BAR_UNHIDE; + mAutoHideController.mSystemUiVisibility = + View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE; + + mAutoHideController.setSystemUiVisibility( + DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect()); + + assertEquals("System UI visibility should not be changed", + expectedStatus, mAutoHideController.mSystemUiVisibility); + verify(mAutoHideController, times(1)).notifySystemUiVisibilityChanged(eq(expectedStatus)); + } + + @Test + public void testSetSystemUiVisibilityWithVisChanged() { + doReturn(true).when(mAutoHideController).hasStatusBar(); + doReturn(true).when(mAutoHideController).hasNavigationBar(); + mAutoHideController.mSystemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN + | View.STATUS_BAR_UNHIDE + | View.NAVIGATION_BAR_UNHIDE; + + mAutoHideController.setSystemUiVisibility( + DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE, + 2, 3, FULL_MASK, null, new Rect()); + + int expectedStatus = View.VISIBLE; + assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility); + verify(mAutoHideController).notifySystemUiVisibilityChanged(eq(expectedStatus)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 1ded6c91f17d..cb5612d165d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -75,7 +75,6 @@ import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.UiOffloadThread; import com.android.systemui.appops.AppOpsController; -import com.android.systemui.appops.AppOpsControllerImpl; import com.android.systemui.assist.AssistManager; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.classifier.FalsingManager; @@ -112,7 +111,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardMonitor; -import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import org.junit.Before; @@ -161,7 +159,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationPresenter mNotificationPresenter; @Mock private NotificationEntryListener mEntryListener; - @Mock private BubbleController mBubbleController; @Mock private NotificationFilter mNotificationFilter; @Mock @@ -192,8 +189,8 @@ public class StatusBarTest extends SysuiTestCase { mViewHierarchyManager); mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager); mDependency.injectTestDependency(NotificationListener.class, mNotificationListener); - mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class)); - mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsControllerImpl.class)); + mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitor.class)); + mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsController.class)); mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController); mDependency.injectTestDependency(DeviceProvisionedController.class, mDeviceProvisionedController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 5786796d980f..96fad21ed7a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -151,7 +151,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATUS_CONNECTED).when(ss).getNrStatus(); + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange(); mPhoneStateListener.onServiceStateChanged(ss); @@ -165,7 +165,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATUS_CONNECTED).when(ss).getNrStatus(); + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss).getNrFrequencyRange(); mPhoneStateListener.onServiceStateChanged(ss); @@ -179,7 +179,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATUS_RESTRICTED).when(ss).getNrStatus(); + doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(ss).getNrState(); mPhoneStateListener.onServiceStateChanged(mServiceState); verifyDataIndicators(TelephonyIcons.ICON_LTE); diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index f106228fc6f0..c5c4b5a7e85b 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -7120,6 +7120,10 @@ message MetricsEvent { // Open: Settings > Special App Access > Do not disturb control for app ZEN_ACCESS_DETAIL = 1692; + // OPEN: Settings > Face > Remove face + // OS: Q + DIALOG_FACE_REMOVE = 1693; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 0d17f22e2edf..1bcc888db7a7 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -1880,6 +1880,33 @@ message WifiUsabilityStatsEntry { PROBE_STATUS_FAILURE = 3; } + // Codes for cellular data network type + enum CellularDataNetworkType { + // Unknown network + NETWORK_TYPE_UNKNOWN = 0; + + // GSM network + NETWORK_TYPE_GSM = 1; + + // CDMA network + NETWORK_TYPE_CDMA = 2; + + // CDMA EVDO network + NETWORK_TYPE_EVDO_0 = 3; + + // WCDMA network + NETWORK_TYPE_UMTS = 4; + + // TDSCDMA network + NETWORK_TYPE_TD_SCDMA = 5; + + // LTE network + NETWORK_TYPE_LTE = 6; + + // NR network + NETWORK_TYPE_NR = 7; + } + // Absolute milliseconds from device boot when these stats were sampled optional int64 time_stamp_ms = 1; @@ -1971,6 +1998,20 @@ message WifiUsabilityStatsEntry { // Whether current entry is for the same BSSID on the same frequency compared // to last entry optional bool is_same_bssid_and_freq = 29; + + // Cellular data network type currently in use on the device for data transmission + optional CellularDataNetworkType cellular_data_network_type = 30; + + // Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp, + // CDMA: Rssi, EVDO: Rssi, GSM: Rssi + optional int32 cellular_signal_strength_dbm = 31; + + // Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid, + // CDMA: Ecio, EVDO: SNR, GSM: invalid */ + optional int32 cellular_signal_strength_db = 32; + + // Whether the primary registered cell of current entry is same as that of previous entry + optional bool is_same_registered_cell = 33; } message WifiUsabilityStats { diff --git a/services/Android.bp b/services/Android.bp index 31385edd015f..567efac5753c 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -26,7 +26,6 @@ java_library { "services.contentsuggestions", "services.coverage", "services.devicepolicy", - "services.ipmemorystore", "services.midi", "services.net", "services.print", diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index 65e31f3acf14..1e3f20ecd01a 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -809,13 +809,9 @@ class TouchExplorer extends BaseEventStreamTransformation // Announce the end of the gesture recognition. sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END); + // Don't announce the end of a the touch interaction if users didn't lift their fingers. if (interactionEnd) { - // Announce the end of a the touch interaction. sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); - } else { - // If gesture detection is end, but user doesn't release the finger, announce the - // transition to exploration state. - sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START); } mExitGestureDetectionModeDelayed.cancel(); @@ -1151,10 +1147,7 @@ class TouchExplorer extends BaseEventStreamTransformation public void run() { // Announce the end of gesture recognition. sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END); - // Clearing puts is in touch exploration state with a finger already - // down, so announce the transition to exploration state. clear(); - sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 4bb805564f09..dd3efa0b4afa 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -890,8 +890,6 @@ final class AutofillManagerServiceImpl } else { pw.println(); mInfo.dump(prefix2, pw); - pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked()); - pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked()); } pw.print(prefix); pw.print("Default component: "); pw.println(getContext() .getString(R.string.config_defaultAutofillService)); diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index aaba1edc73d6..3c17ac35f624 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -16,6 +16,8 @@ package com.android.server.autofill; +import static com.android.server.autofill.Helper.sDebug; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -26,6 +28,7 @@ import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.IBinder; +import android.os.ICancellationSignal; import android.os.RemoteException; import android.os.SystemClock; import android.service.autofill.augmented.AugmentedAutofillService; @@ -142,6 +145,16 @@ final class RemoteAugmentedAutofillService scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest()); } + private void dispatchOnFillTimeout(@NonNull ICancellationSignal cancellation) { + mHandler.post(() -> { + try { + cancellation.cancel(); + } catch (RemoteException e) { + Slog.w(mTag, "Error calling cancellation signal: " + e); + } + }); + } + // TODO(b/123100811): inline into PendingAutofillRequest if it doesn't have any other subclass private abstract static class MyPendingRequest extends PendingRequest<RemoteAugmentedAutofillService, IAugmentedAutofillService> { @@ -161,6 +174,7 @@ final class RemoteAugmentedAutofillService private final int mTaskId; private final long mRequestTime = SystemClock.elapsedRealtime(); private final @NonNull IFillCallback mCallback; + private ICancellationSignal mCancellation; protected PendingAutofillRequest(@NonNull RemoteAugmentedAutofillService service, int sessionId, @NonNull IAutoFillManagerClient client, int taskId, @@ -178,11 +192,55 @@ final class RemoteAugmentedAutofillService if (!finish()) return; // NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks } + + @Override + public void onCancellable(ICancellationSignal cancellation) { + synchronized (mLock) { + final boolean cancelled; + synchronized (mLock) { + mCancellation = cancellation; + cancelled = isCancelledLocked(); + } + if (cancelled) { + try { + cancellation.cancel(); + } catch (RemoteException e) { + Slog.e(mTag, "Error requesting a cancellation", e); + } + } + } + } + + @Override + public boolean isCompleted() { + return isRequestCompleted(); + } + + @Override + public void cancel() { + synchronized (mLock) { + final boolean cancelled = isCancelledLocked(); + final ICancellationSignal cancellation = mCancellation; + if (!cancelled) { + try { + cancellation.cancel(); + } catch (RemoteException e) { + Slog.e(mTag, "Error requesting a cancellation", e); + } + } + } + } }; } @Override public void run() { + synchronized (mLock) { + if (isCancelledLocked()) { + if (sDebug) Slog.d(mTag, "run() called after canceled"); + return; + } + } final RemoteAugmentedAutofillService remoteService = getService(); if (remoteService == null) return; @@ -215,8 +273,33 @@ final class RemoteAugmentedAutofillService Slog.w(TAG, "PendingAutofillRequest timed out (" + remoteService.mRequestTimeoutMs + "ms) for " + remoteService); // NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks + final ICancellationSignal cancellation; + synchronized (mLock) { + cancellation = mCancellation; + } + if (cancellation != null) { + remoteService.dispatchOnFillTimeout(cancellation); + } finish(); } + + @Override + public boolean cancel() { + if (!super.cancel()) return false; + + final ICancellationSignal cancellation; + synchronized (mLock) { + cancellation = mCancellation; + } + if (cancellation != null) { + try { + cancellation.cancel(); + } catch (RemoteException e) { + Slog.e(mTag, "Error cancelling a fill request", e); + } + } + return true; + } } public interface RemoteAugmentedAutofillServiceCallbacks diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index c423f9c87d29..d7d97b39959f 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -27,12 +27,10 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTE import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE; -import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; -import android.app.AppGlobals; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.content.ComponentName; @@ -44,12 +42,12 @@ import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; -import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.service.contentcapture.ActivityEvent; import android.service.contentcapture.ActivityEvent.ActivityEventType; import android.service.contentcapture.ContentCaptureService; +import android.service.contentcapture.ContentCaptureServiceInfo; import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.SnapshotData; import android.util.ArrayMap; @@ -107,6 +105,9 @@ final class ContentCapturePerUserService @GuardedBy("mLock") private boolean mZombie; + @GuardedBy("mLock") + private ContentCaptureServiceInfo mInfo; + // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's ContentCapturePerUserService(@NonNull ContentCaptureManagerService master, @@ -144,33 +145,9 @@ final class ContentCapturePerUserService @Override // from PerUserSystemService protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) throws NameNotFoundException { - - int flags = PackageManager.GET_META_DATA; - final boolean isTemp = isTemporaryServiceSetLocked(); - if (!isTemp) { - flags |= PackageManager.MATCH_SYSTEM_ONLY; - } - - ServiceInfo si; - try { - si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, flags, mUserId); - } catch (RemoteException e) { - Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e); - return null; - } - if (si == null) { - Slog.w(TAG, "Could not get serviceInfo for " + (isTemp ? " (temp)" : "(default system)") - + " " + serviceComponent.flattenToShortString()); - return null; - } - if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) { - Slog.w(TAG, "ContentCaptureService from '" + si.packageName - + "' does not require permission " - + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); - throw new SecurityException("Service does not require permission " - + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); - } - return si; + mInfo = new ContentCaptureServiceInfo(getContext(), serviceComponent, + isTemporaryServiceSetLocked(), mUserId); + return mInfo.getServiceInfo(); } @Override // from PerUserSystemService @@ -490,9 +467,16 @@ final class ContentCapturePerUserService protected void dumpLocked(String prefix, PrintWriter pw) { super.dumpLocked(prefix, pw); + final String prefix2 = prefix + " "; + pw.print(prefix); pw.print("Service Info: "); + if (mInfo == null) { + pw.println("N/A"); + } else { + pw.println(); + mInfo.dump(prefix2, pw); + } pw.print(prefix); pw.print("Zombie: "); pw.println(mZombie); - final String prefix2 = prefix + " "; if (mRemoteService != null) { pw.print(prefix); pw.println("remote service:"); mRemoteService.dump(prefix2, pw); diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index a400cc384a58..3d918fc052c8 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -83,6 +83,7 @@ import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.StatsLog; import android.util.TimeUtils; @@ -195,6 +196,7 @@ class AlarmManagerService extends SystemService { private final Injector mInjector; int mBroadcastRefCount = 0; PowerManager.WakeLock mWakeLock; + SparseIntArray mAlarmsPerUid = new SparseIntArray(); ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>(); ArrayList<InFlight> mInFlight = new ArrayList<>(); private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners = @@ -393,6 +395,8 @@ class AlarmManagerService extends SystemService { @VisibleForTesting static final String KEY_LISTENER_TIMEOUT = "listener_timeout"; @VisibleForTesting + static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid"; + @VisibleForTesting static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled"; private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window"; @VisibleForTesting @@ -420,6 +424,7 @@ class AlarmManagerService extends SystemService { private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000; private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000; private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000; + private static final int DEFAULT_MAX_ALARMS_PER_UID = 500; private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true; private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000; // 1 hr /** @@ -461,6 +466,8 @@ class AlarmManagerService extends SystemService { // Direct alarm listener callback timeout public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT; + public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID; + public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED; public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW; @@ -549,6 +556,15 @@ class AlarmManagerService extends SystemService { APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i], Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i])); } + + MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID, + DEFAULT_MAX_ALARMS_PER_UID); + if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) { + Slog.w(TAG, "Cannot set " + KEY_MAX_ALARMS_PER_UID + " lower than " + + DEFAULT_MAX_ALARMS_PER_UID); + MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID; + } + updateAllowWhileIdleWhitelistDurationLocked(); } } @@ -590,6 +606,9 @@ class AlarmManagerService extends SystemService { TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw); pw.println(); + pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("="); + pw.println(MAX_ALARMS_PER_UID); + for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) { pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("="); TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw); @@ -671,12 +690,6 @@ class AlarmManagerService extends SystemService { final ArrayList<Alarm> alarms = new ArrayList<Alarm>(); - Batch() { - start = 0; - end = Long.MAX_VALUE; - flags = 0; - } - Batch(Alarm seed) { start = seed.whenElapsed; end = clampPositive(seed.maxWhenElapsed); @@ -728,11 +741,16 @@ class AlarmManagerService extends SystemService { return newStart; } + /** + * Remove an alarm from this batch. + * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it + * does not update {@link #mAlarmsPerUid} + */ boolean remove(Alarm alarm) { - return remove(a -> (a == alarm)); + return remove(a -> (a == alarm), true); } - boolean remove(Predicate<Alarm> predicate) { + boolean remove(Predicate<Alarm> predicate, boolean reOrdering) { boolean didRemove = false; long newStart = 0; // recalculate endpoints as we go long newEnd = Long.MAX_VALUE; @@ -741,6 +759,9 @@ class AlarmManagerService extends SystemService { Alarm alarm = alarms.get(i); if (predicate.test(alarm)) { alarms.remove(i); + if (!reOrdering) { + decrementAlarmCount(alarm.uid); + } didRemove = true; if (alarm.alarmClock != null) { mNextAlarmClockMayChange = true; @@ -1734,6 +1755,15 @@ class AlarmManagerService extends SystemService { + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed + " interval=" + interval + " flags=0x" + Integer.toHexString(flags)); } + if (mAlarmsPerUid.get(callingUid, 0) >= mConstants.MAX_ALARMS_PER_UID) { + final String errorMsg = + "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID + + " reached for uid: " + UserHandle.formatUid(callingUid) + + ", callingPackage: " + callingPackage; + // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release. + Slog.wtf(TAG, errorMsg); + throw new UnsupportedOperationException(errorMsg); + } setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed, interval, operation, directReceiver, listenerTag, flags, true, workSource, alarmClock, callingUid, callingPackage); @@ -1756,6 +1786,7 @@ class AlarmManagerService extends SystemService { } catch (RemoteException e) { } removeLocked(operation, directReceiver); + incrementAlarmCount(a.uid); setImplLocked(a, false, doValidate); } @@ -2197,7 +2228,6 @@ class AlarmManagerService extends SystemService { ? sdf.format(new Date(nowRTC - (nowELAPSED - time))) : "-"); } while (i != mNextTickHistory); - pw.println(); } SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class); @@ -2305,6 +2335,18 @@ class AlarmManagerService extends SystemService { if (!blocked) { pw.println(" none"); } + pw.println(); + pw.print(" Pending alarms per uid: ["); + for (int i = 0; i < mAlarmsPerUid.size(); i++) { + if (i > 0) { + pw.print(", "); + } + UserHandle.formatUid(pw, mAlarmsPerUid.keyAt(i)); + pw.print(":"); + pw.print(mAlarmsPerUid.valueAt(i)); + } + pw.println("]"); + pw.println(); mAppWakeupHistory.dump(pw, " ", nowELAPSED); @@ -3046,7 +3088,7 @@ class AlarmManagerService extends SystemService { final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver); for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(whichAlarms); + didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -3098,7 +3140,7 @@ class AlarmManagerService extends SystemService { final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(whichAlarms); + didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -3145,7 +3187,7 @@ class AlarmManagerService extends SystemService { final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches); for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(whichAlarms); + didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -3183,6 +3225,7 @@ class AlarmManagerService extends SystemService { } } + // Only called for ephemeral apps void removeForStoppedLocked(final int uid) { if (uid == Process.SYSTEM_UID) { Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid); @@ -3200,7 +3243,7 @@ class AlarmManagerService extends SystemService { }; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(whichAlarms); + didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -3237,7 +3280,7 @@ class AlarmManagerService extends SystemService { (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(whichAlarms); + didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -3407,8 +3450,7 @@ class AlarmManagerService extends SystemService { return mConstants.ALLOW_WHILE_IDLE_LONG_TIME; } - boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, - final long nowRTC) { + boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) { boolean hasWakeup = false; // batches are temporally sorted, so we need only pull from the // start of the list until we either empty it or hit a batch @@ -3984,7 +4026,7 @@ class AlarmManagerService extends SystemService { } mLastTrigger = nowELAPSED; - boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); + boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED); if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { // if there are no wakeup alarms and the screen is off, we can // delay what we have so far until the future. @@ -4108,9 +4150,8 @@ class AlarmManagerService extends SystemService { case ALARM_EVENT: { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); synchronized (mLock) { - final long nowRTC = mInjector.getCurrentTimeMillis(); final long nowELAPSED = mInjector.getElapsedRealtime(); - triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); + triggerAlarmsLocked(triggerList, nowELAPSED); updateNextAlarmClockLocked(); } @@ -4719,7 +4760,7 @@ class AlarmManagerService extends SystemService { mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage, UserHandle.getUserId(alarm.creatorUid), nowELAPSED); } - + decrementAlarmCount(alarm.uid); final BroadcastStats bs = inflight.mBroadcastStats; bs.count++; if (bs.nesting == 0) { @@ -4747,6 +4788,27 @@ class AlarmManagerService extends SystemService { } } + private void incrementAlarmCount(int uid) { + final int uidIndex = mAlarmsPerUid.indexOfKey(uid); + if (uidIndex >= 0) { + mAlarmsPerUid.setValueAt(uidIndex, mAlarmsPerUid.valueAt(uidIndex) + 1); + } else { + mAlarmsPerUid.put(uid, 1); + } + } + + private void decrementAlarmCount(int uid) { + final int uidIndex = mAlarmsPerUid.indexOfKey(uid); + if (uidIndex >= 0) { + final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1; + if (newCount > 0) { + mAlarmsPerUid.setValueAt(uidIndex, newCount); + } else { + mAlarmsPerUid.removeAt(uidIndex); + } + } + } + private class ShellCmd extends ShellCommand { IAlarmManager getBinderService() { diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 3ab3c349c57b..833faa6f3faf 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -115,7 +115,8 @@ import java.util.stream.Collectors; * * Test: atest com.android.server.DeviceIdleControllerTest * - * Current idling state machine (as of Android 9 Pie). This can be visualized using Graphviz: + * Current idling state machine (as of Android Q). This can be visualized using Graphviz: + <pre> digraph { subgraph deep { @@ -259,6 +260,7 @@ import java.util.stream.Collectors; ] } } + </pre> */ public class DeviceIdleController extends SystemService implements AnyMotionDetector.DeviceIdleCallback { diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 7fab2b96ddbe..6ef5b547a353 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -102,6 +102,7 @@ import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; import com.android.server.location.GnssBatchingProvider; import com.android.server.location.GnssLocationProvider; +import com.android.server.location.GnssMeasurementCorrectionsProvider; import com.android.server.location.GnssMeasurementsProvider; import com.android.server.location.GnssNavigationMessageProvider; import com.android.server.location.GnssStatusListenerHelper; @@ -195,6 +196,7 @@ public class LocationManagerService extends ILocationManager.Stub { private PassiveProvider mPassiveProvider; // track passive provider for special cases private LocationBlacklist mBlacklist; private GnssMeasurementsProvider mGnssMeasurementsProvider; + private GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider; private GnssNavigationMessageProvider mGnssNavigationMessageProvider; @GuardedBy("mLock") private String mLocationControllerExtraPackage; @@ -309,9 +311,13 @@ public class LocationManagerService extends ILocationManager.Stub { AppOpsManager.WATCH_FOREGROUND_CHANGES, new AppOpsManager.OnOpChangedInternalListener() { public void onOpChanged(int op, String packageName) { - synchronized (mLock) { - onAppOpChangedLocked(); - } + // onOpChanged invoked on ui thread, move to our thread to reduce risk of + // blocking ui thread + mHandler.post(() -> { + synchronized (mLock) { + onAppOpChangedLocked(); + } + }); } }); mPackageManager.addOnPermissionsChangeListener( @@ -757,6 +763,8 @@ public class LocationManagerService extends ILocationManager.Stub { mGnssStatusProvider = gnssProvider.getGnssStatusProvider(); mNetInitiatedListener = gnssProvider.getNetInitiatedListener(); mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider(); + mGnssMeasurementCorrectionsProvider = + gnssProvider.getGnssMeasurementCorrectionsProvider(); mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider(); mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy(); } @@ -2921,22 +2929,28 @@ public class LocationManagerService extends ILocationManager.Stub { mContext.enforceCallingPermission( android.Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to inject GNSS measurement corrections."); - if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) { + if (!hasGnssPermissions(packageName)) { Slog.e(TAG, "Can not inject GNSS corrections due to no permission."); - } else { - mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections); + return; + } + if (mGnssMeasurementCorrectionsProvider == null) { + Slog.e(TAG, "Can not inject GNSS corrections. GNSS measurement corrections provider " + + "not available."); + return; } + mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections( + measurementCorrections); } @Override public int getGnssCapabilities(String packageName) { mContext.enforceCallingPermission( android.Manifest.permission.LOCATION_HARDWARE, - "Location Hardware permission not granted to obrain GNSS chipset capabilities."); - if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) { + "Location Hardware permission not granted to obtain GNSS chipset capabilities."); + if (!hasGnssPermissions(packageName) || mGnssMeasurementCorrectionsProvider == null) { return -1; } - return mGnssMeasurementsProvider.getGnssCapabilities(); + return mGnssMeasurementCorrectionsProvider.getCapabilities(); } @Override diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 5582ad77c731..d3298b9238fc 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -62,6 +62,7 @@ import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.TetherStatsParcel; import android.net.UidRange; +import android.net.UidRangeParcel; import android.net.util.NetdService; import android.os.BatteryStats; import android.os.Binder; @@ -80,6 +81,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.telephony.DataConnectionRealTimeInfo; +import android.text.TextUtils; import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; @@ -1028,6 +1030,46 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } + /** + * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname. + */ + private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg, + String iface) { + InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel(); + cfgParcel.ifName = iface; + String hwAddr = cfg.getHardwareAddress(); + if (!TextUtils.isEmpty(hwAddr)) { + cfgParcel.hwAddr = hwAddr; + } else { + cfgParcel.hwAddr = ""; + } + cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress(); + cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength(); + ArrayList<String> flags = new ArrayList<>(); + for (String flag : cfg.getFlags()) { + flags.add(flag); + } + cfgParcel.flags = flags.toArray(new String[0]); + + return cfgParcel; + } + + /** + * Construct InterfaceConfiguration from InterfaceConfigurationParcel. + */ + public static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) { + InterfaceConfiguration cfg = new InterfaceConfiguration(); + cfg.setHardwareAddress(p.hwAddr); + + final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr); + cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength)); + for (String flag : p.flags) { + cfg.setFlag(flag); + } + + return cfg; + } + @Override public InterfaceConfiguration getInterfaceConfig(String iface) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); @@ -1039,7 +1081,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub } try { - final InterfaceConfiguration cfg = InterfaceConfiguration.fromParcel(result); + final InterfaceConfiguration cfg = fromStableParcel(result); return cfg; } catch (IllegalArgumentException iae) { throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae); @@ -1054,7 +1096,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub throw new IllegalStateException("Null LinkAddress given"); } - final InterfaceConfigurationParcel cfgParcel = cfg.toParcel(iface); + final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface); try { mNetdService.interfaceSetCfg(cfgParcel); @@ -1718,12 +1760,27 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } + private static UidRangeParcel makeUidRangeParcel(int start, int stop) { + UidRangeParcel range = new UidRangeParcel(); + range.start = start; + range.stop = stop; + return range; + } + + private static UidRangeParcel[] toStableParcels(UidRange[] ranges) { + UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length]; + for (int i = 0; i < ranges.length; i++) { + stableRanges[i] = makeUidRangeParcel(ranges[i].start, ranges[i].stop); + } + return stableRanges; + } + @Override public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges) throws ServiceSpecificException { mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG); try { - mNetdService.networkRejectNonSecureVpn(add, uidRanges); + mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges)); } catch (ServiceSpecificException e) { Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")" + ": netd command failed", e); @@ -1892,7 +1949,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { - mNetdService.networkAddUidRanges(netId, ranges); + mNetdService.networkAddUidRanges(netId, toStableParcels(ranges)); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); } @@ -1902,7 +1959,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub public void removeVpnUidRanges(int netId, UidRange[] ranges) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { - mNetdService.networkRemoveUidRanges(netId, ranges); + mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges)); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); } @@ -1940,7 +1997,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub private void closeSocketsForFirewallChainLocked(int chain, String chainName) { // UID ranges to close sockets on. - UidRange[] ranges; + UidRangeParcel[] ranges; // UID ranges whose sockets we won't touch. int[] exemptUids; @@ -1948,10 +2005,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName); if (getFirewallType(chain) == FIREWALL_WHITELIST) { // Close all sockets on all non-system UIDs... - ranges = new UidRange[] { + ranges = new UidRangeParcel[] { // TODO: is there a better way of finding all existing users? If so, we could // specify their ranges here. - new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE), + makeUidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE), }; // ... except for the UIDs that have allow rules. synchronized (mRulesLock) { @@ -1978,11 +2035,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub // Close sockets for every UID that has a deny rule... synchronized (mRulesLock) { final SparseIntArray rules = getUidFirewallRulesLR(chain); - ranges = new UidRange[rules.size()]; + ranges = new UidRangeParcel[rules.size()]; for (int i = 0; i < ranges.length; i++) { if (rules.valueAt(i) == FIREWALL_RULE_DENY) { int uid = rules.keyAt(i); - ranges[numUids] = new UidRange(uid, uid); + ranges[numUids] = makeUidRangeParcel(uid, uid); numUids++; } } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index f4161103b699..8cb1ec73a00d 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -208,6 +208,13 @@ class StorageManagerService extends IStorageManager.Stub private static final boolean ENABLE_LEGACY_GREYLIST = SystemProperties .getBoolean(StorageManager.PROP_LEGACY_GREYLIST, true); + /** + * If {@code 1}, enables the isolated storage feature. If {@code -1}, + * disables the isolated storage feature. If {@code 0}, uses the default + * value from the build system. + */ + private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled"; + public static class Lifecycle extends SystemService { private StorageManagerService mStorageManagerService; @@ -797,7 +804,7 @@ class StorageManagerService extends IStorageManager.Stub } }); // For now, simply clone property when it changes - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.Storage.NAMESPACE, + DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_STORAGE, mContext.getMainExecutor(), (namespace, name, value) -> { refreshIsolatedStorageSettings(); }); @@ -837,8 +844,7 @@ class StorageManagerService extends IStorageManager.Stub // Always copy value from newer DeviceConfig location Settings.Global.putString(mResolver, Settings.Global.ISOLATED_STORAGE_REMOTE, - DeviceConfig.getProperty(DeviceConfig.Storage.NAMESPACE, - DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED)); + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE, ISOLATED_STORAGE_ENABLED)); final int local = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ISOLATED_STORAGE_LOCAL, 0); @@ -3741,6 +3747,7 @@ class StorageManagerService extends IStorageManager.Stub case "com.facebook.katana": // b/123996076 case "jp.naver.line.android": // b/124767356 case "com.mxtech.videoplayer.ad": // b/124531483 + case "com.whatsapp": // b/124766614 return Zygote.MOUNT_EXTERNAL_LEGACY; } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index d6fdbe3fd4dc..26896f54f932 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -625,6 +625,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callingPackage = callingPackage; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); + if (r.subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && r.subId != subId) { + throw new IllegalArgumentException( + "PhoneStateListener cannot concurrently listen on multiple " + + "subscriptions. Previously registered on subId: " + r.subId); + } // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID if (!SubscriptionManager.isValidSubscriptionId(subId)) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 82254761817e..97cc756e3924 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1273,11 +1273,13 @@ public class ActivityManagerService extends IActivityManager.Stub static final class ProcessChangeItem { static final int CHANGE_ACTIVITIES = 1<<0; + static final int CHANGE_FOREGROUND_SERVICES = 1<<1; int changes; int uid; int pid; int processState; boolean foregroundActivities; + int foregroundServiceTypes; } static final class UidObserverRegistration { @@ -2935,7 +2937,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (mContentCaptureService != null && (event == Event.ACTIVITY_PAUSED - || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED)) { + || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED + || event == Event.ACTIVITY_DESTROYED)) { mContentCaptureService.notifyActivityEvent(userId, activity, event); } } @@ -3079,6 +3082,13 @@ public class ActivityManagerService extends IActivityManager.Stub observer.onForegroundActivitiesChanged(item.pid, item.uid, item.foregroundActivities); } + if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, + "FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid=" + + item.uid + ": " + item.foregroundServiceTypes); + observer.onForegroundServicesChanged(item.pid, item.uid, + item.foregroundServiceTypes); + } } } catch (RemoteException e) { } @@ -3093,6 +3103,47 @@ public class ActivityManagerService extends IActivityManager.Stub } } + @GuardedBy("this") + ProcessChangeItem enqueueProcessChangeItemLocked(int uid, int pid) { + int i = mPendingProcessChanges.size()-1; + ActivityManagerService.ProcessChangeItem item = null; + while (i >= 0) { + item = mPendingProcessChanges.get(i); + if (item.pid == pid) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, + "Re-using existing item: " + item); + break; + } + i--; + } + + if (i < 0) { + // No existing item in pending changes; need a new one. + final int NA = mAvailProcessChanges.size(); + if (NA > 0) { + item = mAvailProcessChanges.remove(NA-1); + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, + "Retrieving available item: " + item); + } else { + item = new ActivityManagerService.ProcessChangeItem(); + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, + "Allocating new item: " + item); + } + item.changes = 0; + item.pid = pid; + item.uid = uid; + if (mPendingProcessChanges.size() == 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, + "*** Enqueueing dispatch processes changed!"); + mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG) + .sendToTarget(); + } + mPendingProcessChanges.add(item); + } + + return item; + } + private void dispatchProcessDied(int pid, int uid) { int i = mProcessObservers.beginBroadcast(); while (i > 0) { @@ -16275,11 +16326,12 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground, int fgServiceTypes, boolean oomAdj) { + proc.setHasForegroundServices(isForeground, fgServiceTypes); + final boolean hasFgServiceLocationType = (fgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0; if (isForeground != proc.hasForegroundServices() || proc.hasLocationForegroundServices() != hasFgServiceLocationType) { - proc.setHasForegroundServices(isForeground, fgServiceTypes); ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName, proc.info.uid); if (isForeground) { @@ -16308,6 +16360,13 @@ public class ActivityManagerService extends IActivityManager.Stub updateOomAdjLocked(); } } + + if (proc.getForegroundServiceTypes() != fgServiceTypes) { + proc.setReportedForegroundServiceTypes(fgServiceTypes); + ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.info.uid, proc.pid); + item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES; + item.foregroundServiceTypes = fgServiceTypes; + } } // TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update @@ -18101,6 +18160,34 @@ public class ActivityManagerService extends IActivityManager.Stub public void prepareForPossibleShutdown() { ActivityManagerService.this.prepareForPossibleShutdown(); } + + @Override + public boolean hasRunningForegroundService(int uid, int foregroundServicetype) { + synchronized (ActivityManagerService.this) { + for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) { + final ProcessRecord pr = mProcessList.mLruProcesses.get(i); + if (pr.uid != uid) { + continue; + } + + if ((pr.getForegroundServiceTypes() & foregroundServicetype) != 0) { + return true; + } + } + } + + return false; + } + + @Override + public void registerProcessObserver(IProcessObserver processObserver) { + ActivityManagerService.this.registerProcessObserver(processObserver); + } + + @Override + public void unregisterProcessObserver(IProcessObserver processObserver) { + ActivityManagerService.this.unregisterProcessObserver(processObserver); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java index 438538ffde88..9216343e05d8 100644 --- a/services/core/java/com/android/server/am/AppCompactor.java +++ b/services/core/java/com/android/server/am/AppCompactor.java @@ -230,11 +230,8 @@ public final class AppCompactor { */ @GuardedBy("mPhenotypeFlagLock") private void updateUseCompaction() { - String useCompactionFlag = - DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, - KEY_USE_COMPACTION); - mUseCompaction = TextUtils.isEmpty(useCompactionFlag) - ? DEFAULT_USE_COMPACTION : Boolean.parseBoolean(useCompactionFlag); + mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION); if (mUseCompaction && !mCompactionThread.isAlive()) { mCompactionThread.start(); mCompactionHandler = new MemCompactionHandler(); @@ -243,28 +240,11 @@ public final class AppCompactor { @GuardedBy("mPhenotypeFlagLock") private void updateCompactionActions() { - String compactAction1Flag = - DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, - KEY_COMPACT_ACTION_1); - String compactAction2Flag = - DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, - KEY_COMPACT_ACTION_2); - - int compactAction1 = DEFAULT_COMPACT_ACTION_1; - try { - compactAction1 = TextUtils.isEmpty(compactAction1Flag) - ? DEFAULT_COMPACT_ACTION_1 : Integer.parseInt(compactAction1Flag); - } catch (NumberFormatException e) { - // Do nothing, leave default. - } + int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1); - int compactAction2 = DEFAULT_COMPACT_ACTION_2; - try { - compactAction2 = TextUtils.isEmpty(compactAction2Flag) - ? DEFAULT_COMPACT_ACTION_2 : Integer.parseInt(compactAction2Flag); - } catch (NumberFormatException e) { - // Do nothing, leave default. - } + int compactAction2 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2); mCompactActionSome = compactActionIntToString(compactAction1); mCompactActionFull = compactActionIntToString(compactAction2); @@ -312,14 +292,8 @@ public final class AppCompactor { @GuardedBy("mPhenotypeFlagLock") private void updateStatsdSampleRate() { - String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, - KEY_COMPACT_STATSD_SAMPLE_RATE); - try { - mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag) - ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag); - } catch (NumberFormatException e) { - mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; - } + mStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE); mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate)); } diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java index 09df7e20a3e9..d8d6528621d2 100644 --- a/services/core/java/com/android/server/am/AssistDataRequester.java +++ b/services/core/java/com/android/server/am/AssistDataRequester.java @@ -24,6 +24,7 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEI import android.app.ActivityTaskManager; import android.app.AppOpsManager; +import android.app.IActivityTaskManager; import android.app.IAssistDataReceiver; import android.content.Context; import android.graphics.Bitmap; @@ -33,6 +34,7 @@ import android.os.RemoteException; import android.view.IWindowManager; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import java.io.PrintWriter; @@ -50,6 +52,8 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { public static final String KEY_RECEIVER_EXTRA_INDEX = "index"; private IWindowManager mWindowManager; + @VisibleForTesting + public IActivityTaskManager mActivityTaskManager; private Context mContext; private AppOpsManager mAppOpsManager; @@ -128,6 +132,7 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { mCallbacks = callbacks; mCallbacksLock = callbacksLock; mWindowManager = windowManager; + mActivityTaskManager = ActivityTaskManager.getService(); mContext = context; mAppOpsManager = appOpsManager; mRequestStructureAppOps = requestStructureAppOps; @@ -195,8 +200,7 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { // Ensure that the current activity supports assist data boolean isAssistDataAllowed = false; try { - isAssistDataAllowed = - ActivityTaskManager.getService().isAssistDataAllowedOnCurrentActivity(); + isAssistDataAllowed = mActivityTaskManager.isAssistDataAllowedOnCurrentActivity(); } catch (RemoteException e) { // Should never happen } @@ -222,9 +226,9 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i); receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities); boolean result = requestAutofillData - ? ActivityTaskManager.getService().requestAutofillData(this, + ? mActivityTaskManager.requestAutofillData(this, receiverExtras, topActivity, 0 /* flags */) - : ActivityTaskManager.getService().requestAssistContextExtras( + : mActivityTaskManager.requestAssistContextExtras( ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity, /* focused= */ i == 0, /* newSessionId= */ i == 0); if (result) { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 9056f76c4086..aa03de1115b2 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -38,7 +38,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS; import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG; -import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG; import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG; import static com.android.server.am.ActivityManagerService.TAG_BACKUP; import static com.android.server.am.ActivityManagerService.TAG_LRU; @@ -1921,41 +1920,9 @@ public final class OomAdjuster { if (changes != 0) { if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, "Changes in " + app + ": " + changes); - int i = mService.mPendingProcessChanges.size()-1; - ActivityManagerService.ProcessChangeItem item = null; - while (i >= 0) { - item = mService.mPendingProcessChanges.get(i); - if (item.pid == app.pid) { - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, - "Re-using existing item: " + item); - break; - } - i--; - } - if (i < 0) { - // No existing item in pending changes; need a new one. - final int NA = mService.mAvailProcessChanges.size(); - if (NA > 0) { - item = mService.mAvailProcessChanges.remove(NA-1); - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, - "Retrieving available item: " + item); - } else { - item = new ActivityManagerService.ProcessChangeItem(); - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, - "Allocating new item: " + item); - } - item.changes = 0; - item.pid = app.pid; - item.uid = app.info.uid; - if (mService.mPendingProcessChanges.size() == 0) { - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, - "*** Enqueueing dispatch processes changed!"); - mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG) - .sendToTarget(); - } - mService.mPendingProcessChanges.add(item); - } - item.changes |= changes; + ActivityManagerService.ProcessChangeItem item = + mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid); + item.changes = changes; item.foregroundActivities = app.repForegroundActivities; if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, "Item " + Integer.toHexString(System.identityHashCode(item)) diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 51b1ae197821..17b244c75819 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -174,6 +174,7 @@ class ProcessRecord implements WindowProcessListener { boolean hasStartedServices; // Are there any started services running in this process? private boolean mHasForegroundServices; // Running any services that are foreground? private int mFgServiceTypes; // Type of foreground service, if there is a foreground service. + private int mRepFgServiceTypes; // Last reported foreground service types. private boolean mHasForegroundActivities; // Running any activities that are foreground? boolean repForegroundActivities; // Last reported foreground activities. boolean systemNoUi; // This is a system process, but not currently showing UI. @@ -1079,6 +1080,18 @@ class ProcessRecord implements WindowProcessListener { && (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0; } + int getForegroundServiceTypes() { + return mHasForegroundServices ? mFgServiceTypes : 0; + } + + int getReportedForegroundServiceTypes() { + return mRepFgServiceTypes; + } + + void setReportedForegroundServiceTypes(int foregroundServiceTypes) { + mRepFgServiceTypes = foregroundServiceTypes; + } + void setHasForegroundActivities(boolean hasForegroundActivities) { mHasForegroundActivities = hasForegroundActivities; mWindowProcessController.setHasForegroundActivities(hasForegroundActivities); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 029c3fbbcf42..07c9cca3f6c3 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -389,14 +389,14 @@ class UserController implements Handler.Callback { * Step from {@link UserState#STATE_RUNNING_LOCKED} to * {@link UserState#STATE_RUNNING_UNLOCKING}. */ - private void finishUserUnlocking(final UserState uss) { + private boolean finishUserUnlocking(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); // Only keep marching forward if user is actually unlocked - if (!StorageManager.isUserKeyUnlocked(userId)) return; + if (!StorageManager.isUserKeyUnlocked(userId)) return false; synchronized (mLock) { // Do not proceed if unexpected state or a stale user if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) { - return; + return false; } } uss.mUnlockProgress.start(); @@ -427,6 +427,7 @@ class UserController implements Handler.Callback { mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) .sendToTarget(); }); + return true; } /** @@ -1209,7 +1210,10 @@ class UserController implements Handler.Callback { return false; } - finishUserUnlocking(uss); + if (!finishUserUnlocking(uss)) { + notifyFinished(userId, listener); + return false; + } // We just unlocked a user, so let's now attempt to unlock any // managed profiles under that user. diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 7da848c12e83..42a7a5c18a48 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -59,6 +59,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.SystemService; +import java.io.FileDescriptor; import java.io.PrintWriter; /** @@ -103,6 +104,7 @@ public class AttentionManagerService extends SystemService { @Override public void onStart() { + publishBinderService(Context.ATTENTION_SERVICE, new BinderService()); publishLocalService(AttentionManagerInternal.class, new LocalService()); } @@ -111,6 +113,11 @@ public class AttentionManagerService extends SystemService { cancelAndUnbindLocked(peekUserStateLocked(userId)); } + /** Returns {@code true} if attention service is configured on this device. */ + public static boolean isServiceConfigured(Context context) { + return !TextUtils.isEmpty(getServiceConfig(context)); + } + /** Resolves and sets up the attention service if it had not been done yet. */ private boolean isServiceAvailable() { if (mComponentName == null) { @@ -283,6 +290,10 @@ public class AttentionManagerService extends SystemService { return mUserStates.get(userId); } + private static String getServiceConfig(Context context) { + return context.getString(R.string.config_defaultAttentionService); + } + /** * Provides attention service component name at runtime, making sure it's provided by the * system. @@ -291,9 +302,7 @@ public class AttentionManagerService extends SystemService { final String flag = DeviceConfig.getProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, COMPONENT_NAME); - final String componentNameString = flag != null ? flag : context.getString( - R.string.config_defaultAttentionService); - + final String componentNameString = flag != null ? flag : getServiceConfig(context); if (TextUtils.isEmpty(componentNameString)) { return null; } @@ -329,17 +338,15 @@ public class AttentionManagerService extends SystemService { return null; } - private void dumpInternal(PrintWriter pw) { - if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; - IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - ipw.println("Attention Manager Service (dumpsys attention)\n"); + private void dumpInternal(IndentingPrintWriter ipw) { + ipw.println("Attention Manager Service (dumpsys attention) state:\n"); ipw.printPair("context", mContext); - pw.println(); + ipw.println(); synchronized (mLock) { int size = mUserStates.size(); ipw.print("Number user states: "); - pw.println(size); + ipw.println(size); if (size > 0) { ipw.increaseIndent(); for (int i = 0; i < size; i++) { @@ -591,4 +598,15 @@ public class AttentionManagerService extends SystemService { } } } + + private final class BinderService extends Binder { + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) { + return; + } + + dumpInternal(new IndentingPrintWriter(pw, " ")); + } + } } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 69a9e7e842eb..b7746477f0f8 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -170,8 +170,15 @@ import java.util.ArrayList; } } - /*package*/ void setSpeakerphoneOn(boolean on, String eventSource) { + /** + * Turns speakerphone on/off + * @param on + * @param eventSource for logging purposes + * @return true if speakerphone state changed + */ + /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) { synchronized (mDeviceStateLock) { + final boolean wasOn = isSpeakerphoneOn(); if (on) { if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource); @@ -183,6 +190,7 @@ import java.util.ArrayList; mForcedUseForCommExt = mForcedUseForComm; setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource); + return (wasOn != isSpeakerphoneOn()); } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 68f76abe829a..a14a638395db 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3331,7 +3331,11 @@ public class AudioService extends IAudioService.Stub final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on) .append(") from u/pid:").append(Binder.getCallingUid()).append("/") .append(Binder.getCallingPid()).toString(); - mDeviceBroker.setSpeakerphoneOn(on, eventSource); + final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource); + if (stateChanged) { + mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); + } } /** @see AudioManager#isSpeakerphoneOn() */ diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index f313e1d48c53..516844d85484 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -628,6 +628,9 @@ public class BiometricService extends SystemService { null /* description */); // Then give it the bundle to do magic behavior.. intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle); + // Create a new task with this activity located at the root. + intent.setFlags( + Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT); getContext().startActivityAsUser(intent, UserHandle.CURRENT); }); return; diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 45567e5a34cb..ed420b73e79b 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -1417,7 +1417,7 @@ public final class ColorDisplayService extends SystemService { mCurrentColorTemperature = cct; // Adapt the display's nominal white point to match the requested CCT value - mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct); + mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct); mChromaticAdaptationMatrix = ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD, diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java index cd9ebcda009c..ac07e9d6b0b7 100644 --- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java @@ -327,6 +327,10 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst @GuardedBy("mLock") protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { pw.print(prefix); pw.print("User: "); pw.println(mUserId); + if (mServiceInfo != null) { + pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked()); + pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked()); + } if (mMaster.mServiceNameResolver != null) { pw.print(prefix); pw.print("Name resolver: "); mMaster.mServiceNameResolver.dumpShort(pw, mUserId); pw.println(); diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index aca02bf1fb7c..c82084166398 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -30,6 +30,9 @@ import android.net.NetworkInfo; import android.net.NetworkPolicyManager; import android.net.NetworkRequest; import android.net.TrafficStats; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.UserHandle; import android.text.format.DateUtils; import android.util.ArraySet; @@ -85,8 +88,14 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") private final ArraySet<Network> mAvailableNetworks = new ArraySet<>(); + private static final int MSG_DATA_SAVER_TOGGLED = 0; + private static final int MSG_UID_RULES_CHANGES = 1; + + private final Handler mHandler; + public ConnectivityController(JobSchedulerService service) { super(service); + mHandler = new CcHandler(mContext.getMainLooper()); mConnManager = mContext.getSystemService(ConnectivityManager.class); mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); @@ -545,11 +554,39 @@ public final class ConnectivityController extends StateController implements private final INetworkPolicyListener mNetPolicyListener = new NetworkPolicyManager.Listener() { @Override + public void onRestrictBackgroundChanged(boolean restrictBackground) { + if (DEBUG) { + Slog.v(TAG, "onRestrictBackgroundChanged: " + restrictBackground); + } + mHandler.obtainMessage(MSG_DATA_SAVER_TOGGLED).sendToTarget(); + } + + @Override public void onUidRulesChanged(int uid, int uidRules) { if (DEBUG) { Slog.v(TAG, "onUidRulesChanged: " + uid); } - updateTrackedJobs(uid, null); + mHandler.obtainMessage(MSG_UID_RULES_CHANGES, uid, 0).sendToTarget(); + } + }; + + private class CcHandler extends Handler { + CcHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + synchronized (mLock) { + switch (msg.what) { + case MSG_DATA_SAVER_TOGGLED: + updateTrackedJobs(-1, null); + break; + case MSG_UID_RULES_CHANGES: + updateTrackedJobs(msg.arg1, null); + break; + } + } } }; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index c173d660803f..8249999033a4 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -166,9 +166,15 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final int GPS_CAPABILITY_MSA = 0x0000004; private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008; private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010; - private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020; + + // The following three capability flags are removed in IGnssCallback.hal@2.0 and their values + // are marked reserved and not reused in 2.0 to avoid confusion with prior versions. + public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020; public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040; - private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080; + public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080; + + private static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100; + private static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200; // The AGPS SUPL mode private static final int AGPS_SUPL_MODE_MSA = 0x02; @@ -333,7 +339,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private boolean mStarted; // capabilities of the GPS engine - private int mEngineCapabilities; + private volatile int mEngineCapabilities; // true if XTRA is supported private boolean mSupportsXtra; @@ -372,6 +378,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final LocationExtras mLocationExtras = new LocationExtras(); private final GnssStatusListenerHelper mGnssStatusListenerHelper; private final GnssMeasurementsProvider mGnssMeasurementsProvider; + private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider; private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener(); private final LocationChangeListener mFusedLocationListener = new FusedLocationListener(); @@ -437,6 +444,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return mGnssMeasurementsProvider; } + public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() { + return mGnssMeasurementCorrectionsProvider; + } + public GnssNavigationMessageProvider getGnssNavigationMessageProvider() { return mGnssNavigationMessageProvider; } @@ -627,6 +638,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } }; + mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler); + mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) { @Override protected boolean isGpsEnabled() { @@ -1258,6 +1271,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); } + public int getGnssCapabilities() { + return mEngineCapabilities; + } + private boolean hasCapability(int capability) { return ((mEngineCapabilities & capability) != 0); } @@ -1467,22 +1484,27 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } @NativeEntryPoint - private void setEngineCapabilities(final int capabilities) { + private void setEngineCapabilities(final int capabilities, boolean hasSubHalCapabilityFlags) { // send to handler thread for fast native return, and in-order handling - mHandler.post( - () -> { - mEngineCapabilities = capabilities; + mHandler.post(() -> { + mEngineCapabilities = capabilities; - if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { - mNtpTimeHelper.enablePeriodicTimeInjection(); - requestUtcTime(); - } + if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { + mNtpTimeHelper.enablePeriodicTimeInjection(); + requestUtcTime(); + } - mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities); - mGnssNavigationMessageProvider.onCapabilitiesUpdated( - hasCapability(GPS_CAPABILITY_NAV_MESSAGES)); - restartRequests(); - }); + mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities, hasSubHalCapabilityFlags); + mGnssNavigationMessageProvider.onCapabilitiesUpdated(capabilities, + hasSubHalCapabilityFlags); + restartRequests(); + }); + } + + @NativeEntryPoint + private void setMeasurementCorrectionsCapabilities(final int capabilities) { + mHandler.post(() -> mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated( + capabilities)); } private void restartRequests() { @@ -2122,7 +2144,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING "); if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS "); if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES "); + if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE "); + if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST "); s.append(")\n"); + if (mGnssGeofenceProvider.isHardwareGeofenceSupported()) { + s.append(" hasSubHal=GEOFENCING\n"); + } + if (mGnssMeasurementsProvider.isAvailableInPlatform()) { + s.append(" hasSubHal=MEASUREMENTS\n"); + } + if (mGnssNavigationMessageProvider.isAvailableInPlatform()) { + s.append(" hasSubHal=NAV_MESSAGES\n"); + } + if (mGnssMeasurementCorrectionsProvider.isAvailableInPlatform()) { + s.append(" hasSubHal=MEASUREMENT_CORRECTIONS ["); + s.append(mGnssMeasurementCorrectionsProvider.toStringCapabilities()); + s.append("]\n"); + } s.append(mGnssMetrics.dumpGnssMetricsAsText()); s.append(" native internal state: ").append(native_get_internal_state()); s.append("\n"); diff --git a/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java new file mode 100644 index 000000000000..21627876a49e --- /dev/null +++ b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import android.location.GnssMeasurementCorrections; +import android.os.Handler; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Manages GNSS measurement corrections. + * + * <p>Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal} + * and {@code IMeasurementCorrectionsCallback.hal). + * + * @hide + */ +public class GnssMeasurementCorrectionsProvider { + private static final String TAG = "GnssMeasurementCorrectionsProvider"; + + // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal. + private static final int CAPABILITY_LOS_SATS = 0x0000001; + private static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002; + private static final int CAPABILITY_REFLECTING_PLANE = 0x0000004; + + private static final int INVALID_CAPABILITIES = 1 << 31; + + private final Handler mHandler; + private final GnssMeasurementCorrectionsProviderNative mNative; + private volatile int mCapabilities = INVALID_CAPABILITIES; + + GnssMeasurementCorrectionsProvider(Handler handler) { + this(handler, new GnssMeasurementCorrectionsProviderNative()); + } + + @VisibleForTesting + GnssMeasurementCorrectionsProvider(Handler handler, + GnssMeasurementCorrectionsProviderNative aNative) { + mHandler = handler; + mNative = aNative; + } + + /** + * Returns {@code true} if the GNSS HAL implementation supports measurement corrections. + */ + public boolean isAvailableInPlatform() { + return mNative.isMeasurementCorrectionsSupported(); + } + + /** + * Injects GNSS measurement corrections into the GNSS chipset. + * + * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS + * measurement corrections to be injected into the GNSS chipset. + */ + public void injectGnssMeasurementCorrections( + GnssMeasurementCorrections measurementCorrections) { + if (!isCapabilitiesReceived()) { + Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities " + + "not received yet."); + return; + } + mHandler.post(() -> { + if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) { + Log.e(TAG, "Failure in injecting GNSS corrections."); + } + }); + } + + /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */ + void onCapabilitiesUpdated(int capabilities) { + if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities, + CAPABILITY_EXCESS_PATH_LENGTH)) { + mCapabilities = capabilities; + } else { + Log.e(TAG, "Failed to set capabilities. Received capabilities 0x" + + Integer.toHexString(capabilities) + " does not contain the mandatory " + + "LOS_SATS or the EXCESS_PATH_LENGTH capability."); + } + } + + /** + * Returns the measurement corrections specific capabilities of the GNSS HAL implementation. + */ + public int getCapabilities() { + return mCapabilities; + } + + /** + * Returns the string representation of the GNSS measurement capabilities. + */ + String toStringCapabilities() { + final int capabilities = getCapabilities(); + StringBuilder s = new StringBuilder(); + s.append("mCapabilities=0x").append(Integer.toHexString(capabilities)); + s.append(" ( "); + if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) { + s.append("LOS_SATS "); + } + if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) { + s.append("EXCESS_PATH_LENGTH "); + } + if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) { + s.append("REFLECTING_PLANE "); + } + s.append(")"); + return s.toString(); + } + + private boolean isCapabilitiesReceived() { + return mCapabilities != INVALID_CAPABILITIES; + } + + private static boolean hasCapability(int halCapabilities, int capability) { + return (halCapabilities & capability) != 0; + } + + @VisibleForTesting + static class GnssMeasurementCorrectionsProviderNative { + public boolean isMeasurementCorrectionsSupported() { + return native_is_measurement_corrections_supported(); + } + + public boolean injectGnssMeasurementCorrections( + GnssMeasurementCorrections measurementCorrections) { + return native_inject_gnss_measurement_corrections(measurementCorrections); + } + } + + private static native boolean native_is_measurement_corrections_supported(); + + private static native boolean native_inject_gnss_measurement_corrections( + GnssMeasurementCorrections measurementCorrections); +} diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java index 1fc7192916df..844735a02eeb 100644 --- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java @@ -11,13 +11,12 @@ * 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.location; import android.content.Context; -import android.location.GnssMeasurementCorrections; import android.location.GnssMeasurementsEvent; import android.location.IGnssMeasurementsListener; import android.os.Handler; @@ -42,7 +41,6 @@ public abstract class GnssMeasurementsProvider private boolean mIsCollectionStarted; private boolean mEnableFullTracking; - private int mGnssEngineCapabilities; protected GnssMeasurementsProvider(Context context, Handler handler) { this(context, handler, new GnssMeasurementProviderNative()); @@ -87,21 +85,6 @@ public abstract class GnssMeasurementsProvider } } - /** - * Injects GNSS measurement corrections into the GNSS chipset. - * - * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS - * measurement corrections to be injected into the GNSS chipset. - */ - public void injectGnssMeasurementCorrections( - GnssMeasurementCorrections measurementCorrections) { - mHandler.post(() -> { - if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) { - Log.e(TAG, "Failure in injecting GNSS corrections."); - } - }); - } - @Override protected void unregisterFromService() { boolean stopped = mNative.stopMeasurementCollection(); @@ -121,20 +104,20 @@ public abstract class GnssMeasurementsProvider }); } - /** Updates the framework about the capabilities of the GNSS chipset */ - public void onCapabilitiesUpdated(int capabilities) { - mGnssEngineCapabilities = capabilities; - boolean isGnssMeasurementsSupported = - (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0; + /** Handle GNSS capabilities update from the GNSS HAL implementation. */ + public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) { + // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum + // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate + // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the + // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs + // which explicitly set the sub-HAL capability bits must continue to work. + final boolean isGnssMeasurementsSupported = hasSubHalCapabilityFlags + ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0 + : mNative.isMeasurementSupported(); setSupported(isGnssMeasurementsSupported); updateResult(); } - /** Obtains the GNSS engine capabilities. */ - public int getGnssCapabilities() { - return mGnssEngineCapabilities; - } - public void onGpsEnabledChanged() { tryUpdateRegistrationWithService(); updateResult(); @@ -195,11 +178,6 @@ public abstract class GnssMeasurementsProvider public boolean stopMeasurementCollection() { return native_stop_measurement_collection(); } - - public boolean injectGnssMeasurementCorrections( - GnssMeasurementCorrections measurementCorrections) { - return native_inject_gnss_measurement_corrections(measurementCorrections); - } } private static native boolean native_is_measurement_supported(); @@ -207,7 +185,4 @@ public abstract class GnssMeasurementsProvider private static native boolean native_start_measurement_collection(boolean enableFullTracking); private static native boolean native_stop_measurement_collection(); - - private static native boolean native_inject_gnss_measurement_corrections( - GnssMeasurementCorrections measurementCorrections); } diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java index 80a3f9bd2aba..7e8b599129c3 100644 --- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java +++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java @@ -11,7 +11,7 @@ * 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.location; @@ -51,7 +51,6 @@ public abstract class GnssNavigationMessageProvider mNative = aNative; } - // TODO(b/37460011): Use this with death recovery logic. void resumeIfStarted() { if (DEBUG) { Log.d(TAG, "resumeIfStarted"); @@ -92,7 +91,16 @@ public abstract class GnssNavigationMessageProvider ); } - public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) { + /** Handle GNSS capabilities update from the GNSS HAL implementation */ + public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) { + // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum + // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate + // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the + // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs + // which explicitly set the sub-HAL capability bits must continue to work. + final boolean isGnssNavigationMessageSupported = hasSubHalCapabilityFlags + ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES) != 0 + : mNative.isNavigationMessageSupported(); setSupported(isGnssNavigationMessageSupported); updateResult(); } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 192ad6d57d52..7b691b411a99 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -28,6 +28,7 @@ import android.media.MediaParceledListSlice; import android.media.Rating; import android.media.VolumeProvider; import android.media.session.ControllerCallbackLink; +import android.media.session.ISession; import android.media.session.ISessionController; import android.media.session.MediaController; import android.media.session.MediaController.PlaybackInfo; @@ -35,7 +36,6 @@ import android.media.session.MediaSession; import android.media.session.MediaSession.QueueItem; import android.media.session.PlaybackState; import android.media.session.SessionCallbackLink; -import android.media.session.SessionLink; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -45,6 +45,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Process; +import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; import android.util.Log; @@ -81,7 +82,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private final Bundle mSessionInfo; private final ControllerStub mController; private final MediaSession.Token mSessionToken; - private final SessionLink mSession; + private final SessionStub mSession; private final SessionCb mSessionCb; private final MediaSessionService.ServiceImpl mService; private final Context mContext; @@ -133,7 +134,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mSessionInfo = sessionInfo; mController = new ControllerStub(); mSessionToken = new MediaSession.Token(mController); - mSession = new SessionLink(new SessionStub()); + mSession = new SessionStub(); mSessionCb = new SessionCb(cb); mService = service; mContext = mService.getContext(); @@ -144,11 +145,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } /** - * Get the session link for the {@link MediaSession}. + * Get the session binder for the {@link MediaSession}. * - * @return The session link apps talk to. + * @return The session binder apps talk to. */ - public SessionLink getSessionBinder() { + public ISession getSessionBinder() { return mSession; } @@ -818,9 +819,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } }; - private final class SessionStub extends SessionLink.SessionStub { + private final class SessionStub extends ISession.Stub { @Override - public void destroySession() { + public void destroySession() throws RemoteException { final long token = Binder.clearCallingIdentity(); try { mService.destroySession(MediaSessionRecord.this); @@ -830,18 +831,18 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void sendEvent(String event, Bundle data) { + public void sendEvent(String event, Bundle data) throws RemoteException { mHandler.post(MessageHandler.MSG_SEND_EVENT, event, data == null ? null : new Bundle(data)); } @Override - public ISessionController getController() { + public ISessionController getController() throws RemoteException { return mController; } @Override - public void setActive(boolean active) { + public void setActive(boolean active) throws RemoteException { mIsActive = active; final long token = Binder.clearCallingIdentity(); try { @@ -853,7 +854,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setFlags(int flags) { + public void setFlags(int flags) throws RemoteException { if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { int pid = Binder.getCallingPid(); int uid = Binder.getCallingUid(); @@ -872,7 +873,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setMediaButtonReceiver(PendingIntent pi) { + public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException { mMediaButtonReceiver = pi; final long token = Binder.clearCallingIdentity(); try { @@ -883,12 +884,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setLaunchPendingIntent(PendingIntent pi) { + public void setLaunchPendingIntent(PendingIntent pi) throws RemoteException { mLaunchIntent = pi; } @Override - public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) { + public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) + throws RemoteException { synchronized (mLock) { MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata) .build(); @@ -906,7 +908,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setPlaybackState(PlaybackState state) { + public void setPlaybackState(PlaybackState state) throws RemoteException { int oldState = mPlaybackState == null ? PlaybackState.STATE_NONE : mPlaybackState.getState(); int newState = state == null @@ -924,21 +926,21 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setQueue(List<QueueItem> queue) { + public void setQueue(MediaParceledListSlice queue) throws RemoteException { synchronized (mLock) { - mQueue = queue; + mQueue = queue == null ? null : (List<QueueItem>) queue.getList(); } mHandler.post(MessageHandler.MSG_UPDATE_QUEUE); } @Override - public void setQueueTitle(CharSequence title) { + public void setQueueTitle(CharSequence title) throws RemoteException { mQueueTitle = title; mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE); } @Override - public void setExtras(Bundle extras) { + public void setExtras(Bundle extras) throws RemoteException { synchronized (mLock) { mExtras = extras == null ? null : new Bundle(extras); } @@ -946,18 +948,18 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setRatingType(int type) { + public void setRatingType(int type) throws RemoteException { mRatingType = type; } @Override - public void setCurrentVolume(int volume) { + public void setCurrentVolume(int volume) throws RemoteException { mCurrentVolume = volume; mHandler.post(MessageHandler.MSG_UPDATE_VOLUME); } @Override - public void setPlaybackToLocal(AudioAttributes attributes) { + public void setPlaybackToLocal(AudioAttributes attributes) throws RemoteException { boolean typeChanged; synchronized (mLock) { typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE; @@ -980,7 +982,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setPlaybackToRemote(int control, int max) { + public void setPlaybackToRemote(int control, int max) throws RemoteException { boolean typeChanged; synchronized (mLock) { typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL; diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java index 94f289f2e382..7c8dc745f6f7 100644 --- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java @@ -49,12 +49,12 @@ import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyListener; import android.media.session.IOnVolumeKeyLongPressListener; +import android.media.session.ISession; import android.media.session.ISession2TokensListener; import android.media.session.ISessionManager; import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.SessionCallbackLink; -import android.media.session.SessionLink; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -1001,7 +1001,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { private boolean mVoiceButtonHandled = false; @Override - public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag, + public ISession createSession(String packageName, SessionCallbackLink cb, String tag, Bundle sessionInfo, int userId) throws RemoteException { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index 270fbc68e143..3872523492a7 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -17,9 +17,14 @@ package com.android.server.media.projection; import android.Manifest; +import android.app.ActivityManagerInternal; import android.app.AppOpsManager; +import android.app.IProcessObserver; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ServiceInfo; import android.hardware.display.DisplayManager; import android.media.MediaRouter; import android.media.projection.IMediaProjection; @@ -29,6 +34,8 @@ import android.media.projection.IMediaProjectionWatcherCallback; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; import android.os.Binder; +import android.os.Build; +import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -38,6 +45,7 @@ import android.util.ArrayMap; import android.util.Slog; import com.android.internal.util.DumpUtils; +import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.Watchdog; @@ -63,6 +71,8 @@ public final class MediaProjectionManagerService extends SystemService private final Context mContext; private final AppOpsManager mAppOps; + private final ActivityManagerInternal mActivityManagerInternal; + private final PackageManager mPackageManager; private final MediaRouter mMediaRouter; private final MediaRouterCallback mMediaRouterCallback; @@ -77,6 +87,8 @@ public final class MediaProjectionManagerService extends SystemService mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>(); mCallbackDelegate = new CallbackDelegate(); mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); + mPackageManager = mContext.getPackageManager(); mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); mMediaRouterCallback = new MediaRouterCallback(); Watchdog.getInstance().addMonitor(this); @@ -88,6 +100,21 @@ public final class MediaProjectionManagerService extends SystemService false /*allowIsolated*/); mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY); + mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() { + @Override + public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) { + } + + @Override + public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) { + MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid, + serviceTypes); + } + + @Override + public void onProcessDied(int pid, int uid) { + } + }); } @Override @@ -105,6 +132,29 @@ public final class MediaProjectionManagerService extends SystemService synchronized (mLock) { /* check for deadlock */ } } + /** + * Called when the set of active foreground service types for a given {@code uid / pid} changes. + * We will stop the active projection grant if its owner targets {@code Q} or higher and has no + * started foreground services of type {@code FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}. + */ + private void handleForegroundServicesChanged(int pid, int uid, int serviceTypes) { + synchronized (mLock) { + if (mProjectionGrant == null || mProjectionGrant.uid != uid) { + return; + } + + if (mProjectionGrant.targetSdkVersion < VERSION_CODES.Q) { + return; + } + + if ((serviceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) != 0) { + return; + } + + mProjectionGrant.stop(); + } + } + private void startProjectionLocked(final MediaProjection projection) { if (mProjectionGrant != null) { mProjectionGrant.stop(); @@ -229,10 +279,19 @@ public final class MediaProjectionManagerService extends SystemService if (packageName == null || packageName.isEmpty()) { throw new IllegalArgumentException("package name must not be empty"); } + long callingToken = Binder.clearCallingIdentity(); + MediaProjection projection; try { - projection = new MediaProjection(type, uid, packageName); + ApplicationInfo ai; + try { + ai = mPackageManager.getApplicationInfo(packageName, 0); + } catch (NameNotFoundException e) { + throw new IllegalArgumentException("No package matching :" + packageName); + } + + projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion); if (isPermanentGrant) { mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA, projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED); @@ -334,17 +393,19 @@ public final class MediaProjectionManagerService extends SystemService public final int uid; public final String packageName; public final UserHandle userHandle; + public final int targetSdkVersion; private IMediaProjectionCallback mCallback; private IBinder mToken; private IBinder.DeathRecipient mDeathEater; private int mType; - public MediaProjection(int type, int uid, String packageName) { + MediaProjection(int type, int uid, String packageName, int targetSdkVersion) { mType = type; this.uid = uid; this.packageName = packageName; userHandle = new UserHandle(UserHandle.getUserId(uid)); + this.targetSdkVersion = targetSdkVersion; } @Override // Binder call @@ -400,6 +461,14 @@ public final class MediaProjectionManagerService extends SystemService + " attempted to start already started MediaProjection"); return; } + + if (targetSdkVersion >= Build.VERSION_CODES.Q + && !mActivityManagerInternal.hasRunningForegroundService( + uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) { + throw new SecurityException("Media projections require a foreground service" + + " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION"); + } + mCallback = callback; registerCallback(mCallback); try { diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index d9ab13295166..de9312041c41 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -438,6 +438,8 @@ public final class NotificationRecord { if (getAudioAttributes() != null) { getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES); } + proto.write(NotificationRecordProto.PACKAGE, sbn.getPackageName()); + proto.write(NotificationRecordProto.DELEGATE_PACKAGE, sbn.getOpPkg()); proto.end(token); } @@ -458,6 +460,7 @@ public final class NotificationRecord { pw.println(prefix + this); prefix = prefix + " "; pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId()); + pw.println(prefix + "opPkg=" + sbn.getOpPkg()); pw.println(prefix + "icon=" + iconStr); pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags)); pw.println(prefix + "pri=" + notification.priority); diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 8905eb947eab..37dd63a2f745 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -758,7 +758,7 @@ public final class OverlayManagerService extends SystemService { * @throws SecurityException if the permission check fails */ private void enforceChangeOverlayPackagesPermission(@NonNull final String message) { - getContext().enforceCallingPermission( + getContext().enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message); } @@ -769,7 +769,7 @@ public final class OverlayManagerService extends SystemService { * @throws SecurityException if the permission check fails */ private void enforceDumpPermission(@NonNull final String message) { - getContext().enforceCallingPermission(android.Manifest.permission.DUMP, message); + getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message); } }; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 181b7a2af8b0..ad17549d7448 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -123,6 +123,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements /** Automatically destroy sessions older than this */ private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; + /** Automatically destroy staged sessions that have not changed state in this time */ + private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS; /** Upper bound on number of active sessions for a UID */ private static final long MAX_ACTIVE_SESSIONS = 1024; /** Upper bound on number of historical sessions for a UID */ @@ -357,11 +359,19 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } final long age = System.currentTimeMillis() - session.createdMillis; - + final long timeSinceUpdate = + System.currentTimeMillis() - session.updatedMillis; final boolean valid; - if (age >= MAX_AGE_MILLIS) { - Slog.w(TAG, "Abandoning old session first created at " - + session.createdMillis); + if (session.isStaged()) { + if (timeSinceUpdate >= MAX_TIME_SINCE_UPDATE_MILLIS + && session.isStagedAndInTerminalState()) { + valid = false; + } else { + valid = true; + } + } else if (age >= MAX_AGE_MILLIS) { + Slog.w(TAG, "Abandoning old session created at " + + session.createdMillis); valid = false; } else { valid = true; @@ -1196,6 +1206,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } public void onStagedSessionChanged(PackageInstallerSession session) { + session.markUpdated(); writeSessionsAsync(); if (mOkToSendBroadcasts) { mPm.sendSessionUpdatedBroadcast(session.generateInfo(false), diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 6451b5653fe3..66b530f19ed8 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -144,6 +144,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; private static final String ATTR_INSTALLER_UID = "installerUid"; private static final String ATTR_CREATED_MILLIS = "createdMillis"; + private static final String ATTR_UPDATED_MILLIS = "updatedMillis"; private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; private static final String ATTR_PREPARED = "prepared"; @@ -199,6 +200,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final Object mLock = new Object(); + /** Timestamp of the last time this session changed state */ + @GuardedBy("mLock") + long updatedMillis; + /** Uid of the creator of this session. */ private final int mOriginalInstallerUid; @@ -422,6 +427,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mInstallerUid = installerUid; this.params = params; this.createdMillis = createdMillis; + this.updatedMillis = createdMillis; this.stageDir = stageDir; this.stageCid = stageCid; if (childSessionIds != null) { @@ -521,6 +527,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** Returns true if a staged session has reached a final state and can be forgotten about */ + public boolean isStagedAndInTerminalState() { + synchronized (mLock) { + return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed); + } + } + @GuardedBy("mLock") private void assertPreparedAndNotSealedLocked(String cookie) { assertPreparedAndNotCommittedOrDestroyedLocked(cookie); @@ -1034,6 +1047,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** Update the timestamp of when the staged session last changed state */ + public void markUpdated() { + synchronized (mLock) { + this.updatedMillis = System.currentTimeMillis(); + } + } + @Override public void transfer(String packageName) { Preconditions.checkNotNull(packageName); @@ -2114,7 +2134,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void destroyInternal() { synchronized (mLock) { mSealed = true; - if (!params.isStaged) { + if (!params.isStaged || isStagedAndInTerminalState()) { mDestroyed = true; } // Force shut down all bridges @@ -2224,6 +2244,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mInstallerPackageName); writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid); writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis); + writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis); if (stageDir != null) { writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, stageDir.getAbsolutePath()); @@ -2326,6 +2347,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid( installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)); final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS); + long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS); final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java index a9126c0caa74..031b5ce3d5b9 100644 --- a/services/core/java/com/android/server/pm/PackageKeySetData.java +++ b/services/core/java/com/android/server/pm/PackageKeySetData.java @@ -107,10 +107,7 @@ public class PackageKeySetData { } protected void removeAllDefinedKeySets() { - final int aliasSize = mKeySetAliases.size(); - for (int i = 0; i < aliasSize; i++) { - mKeySetAliases.removeAt(i); - } + mKeySetAliases.erase(); } protected boolean isUsingDefinedKeySets() { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4e8ef7100466..ec2ff28b4a88 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -552,10 +552,21 @@ public class PackageManagerService extends IPackageManager.Stub private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000; /** + * Timeout duration in milliseconds for enabling package rollback. If we fail to enable + * rollback within that period, the install will proceed without rollback enabled. + * + * <p>If flag value is negative, the default value will be assigned. + * + * Flag type: {@code long} + * Namespace: NAMESPACE_ROLLBACK + */ + private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout"; + + /** * The default duration to wait for rollback to be enabled in * milliseconds. */ - private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT = 10 * 1000; + private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000; /** * The default response for package verification timeout. @@ -14754,11 +14765,11 @@ public class PackageManagerService extends IPackageManager.Stub public void onReceive(Context context, Intent intent) { // the duration to wait for rollback to be enabled, in millis long rollbackTimeout = DeviceConfig.getLong( - DeviceConfig.Rollback.NAMESPACE, - DeviceConfig.Rollback.ENABLE_ROLLBACK_TIMEOUT, - DEFAULT_ENABLE_ROLLBACK_TIMEOUT); + DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, + DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS); if (rollbackTimeout < 0) { - rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT; + rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS; } final Message msg = mHandler.obtainMessage( ENABLE_ROLLBACK_TIMEOUT); @@ -20162,21 +20173,20 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public String getContentCaptureServicePackageName() { - String contentCaptureServiceName = - mContext.getString(R.string.config_defaultContentCaptureService); + public String getSystemCaptionsServicePackageName() { + String flattenedSystemCaptionsServiceComponentName = + mContext.getString(R.string.config_defaultSystemCaptionsService); - if (TextUtils.isEmpty(contentCaptureServiceName)) { + if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) { return null; } - int separatorIndex = contentCaptureServiceName.indexOf("/"); - - if (separatorIndex < 0) { + ComponentName systemCaptionsServiceComponentName = + ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName); + if (systemCaptionsServiceComponentName == null) { return null; } - - return contentCaptureServiceName.substring(0, separatorIndex); + return systemCaptionsServiceComponentName.getPackageName(); } public String getIncidentReportApproverPackageName() { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index aced1a2adf66..459de1a71898 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2693,6 +2693,7 @@ public final class Settings { // seinfo - seinfo label for the app (assigned at install time) // gids - supplementary gids this app launches with // profileableFromShellFlag - 0 or 1 if the package is profileable from shell. + // longVersionCode - integer version of the package. // // NOTE: We prefer not to expose all ApplicationInfo flags for now. // @@ -2720,6 +2721,8 @@ public final class Settings { } sb.append(" "); sb.append(ai.isProfileableByShell() ? "1" : "0"); + sb.append(" "); + sb.append(String.valueOf(ai.longVersionCode)); sb.append("\n"); writer.append(sb); } diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index e9077a9df9cf..0a17e1305f03 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -748,11 +748,11 @@ public final class DefaultPermissionGrantPolicy { grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId, STORAGE_PERMISSIONS); - // Content Capture Service - String contentCaptureServicePackageName = - mContext.getPackageManager().getContentCaptureServicePackageName(); - if (!TextUtils.isEmpty(contentCaptureServicePackageName)) { - grantPermissionsToSystemPackage(contentCaptureServicePackageName, userId, + // System Captions Service + String systemCaptionsServicePackageName = + mContext.getPackageManager().getSystemCaptionsServicePackageName(); + if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) { + grantPermissionsToSystemPackage(systemCaptionsServicePackageName, userId, MICROPHONE_PERMISSIONS); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 58106367842a..e7c9a0819896 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -104,7 +104,6 @@ import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.IUiModeManager; @@ -5114,6 +5113,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { awakenDreams(); } + // Start dock. Intent dock = createHomeDockIntent(); if (dock != null) { try { @@ -5126,21 +5126,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - Intent intent; - - if (fromHomeKey) { - intent = new Intent(mHomeIntent); - intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey); - } else { - intent = mHomeIntent; - } - final Bundle bundle = getLaunchDisplayIdBundle(displayId); - startActivityAsUser(intent, bundle, UserHandle.CURRENT); - } - - private @Nullable Bundle getLaunchDisplayIdBundle(int displayId) { - return (displayId == INVALID_DISPLAY) ? null - : ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); + // Start home. + mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, "startDockOrHome", + displayId, fromHomeKey); } /** diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index 406cbc10a8aa..701e5af01290 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -269,7 +269,7 @@ public class AttentionDetector { */ @VisibleForTesting boolean isAttentionServiceSupported() { - return mAttentionManager.isAttentionServiceSupported(); + return mAttentionManager != null && mAttentionManager.isAttentionServiceSupported(); } public void dump(PrintWriter pw) { diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index 5adcf352e260..f0e462503769 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -115,9 +115,41 @@ public class BatterySaverController implements BatterySaverPolicyListener { public static final int REASON_SETTING_CHANGED = 8; public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9; public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10; - public static final int REASON_STICKY_RESTORE_OFF = 11; - public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 12; - public static final int REASON_TIMEOUT = 13; + public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11; + public static final int REASON_TIMEOUT = 12; + + static String reasonToString(int reason) { + switch (reason) { + case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON: + return "Percentage Auto ON"; + case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF: + return "Percentage Auto OFF"; + case BatterySaverController.REASON_MANUAL_ON: + return "Manual ON"; + case BatterySaverController.REASON_MANUAL_OFF: + return "Manual OFF"; + case BatterySaverController.REASON_STICKY_RESTORE: + return "Sticky restore"; + case BatterySaverController.REASON_INTERACTIVE_CHANGED: + return "Interactivity changed"; + case BatterySaverController.REASON_POLICY_CHANGED: + return "Policy changed"; + case BatterySaverController.REASON_PLUGGED_IN: + return "Plugged in"; + case BatterySaverController.REASON_SETTING_CHANGED: + return "Setting changed"; + case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON: + return "Dynamic Warning Auto ON"; + case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF: + return "Dynamic Warning Auto OFF"; + case BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED: + return "Adaptive Power Savings changed"; + case BatterySaverController.REASON_TIMEOUT: + return "timeout"; + default: + return "Unknown reason: " + reason; + } + } /** * Plugin interface. All methods are guaranteed to be called on the same (handler) thread. diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java index af5d40bfbcec..8f2e997d319e 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java @@ -15,6 +15,8 @@ */ package com.android.server.power.batterysaver; +import static com.android.server.power.batterysaver.BatterySaverController.reasonToString; + import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -49,6 +51,42 @@ import java.io.PrintWriter; * Do not call out with the lock held. (Settings provider is okay.) * * Test: atest com.android.server.power.batterysaver.BatterySaverStateMachineTest + * + * Current state machine. This can be visualized using Graphviz: + <pre> + + digraph { + STATE_OFF + STATE_MANUAL_ON [label="STATE_MANUAL_ON\nTurned on manually by the user"] + STATE_AUTOMATIC_ON [label="STATE_AUTOMATIC_ON\nTurned on automatically by the system"] + STATE_OFF_AUTOMATIC_SNOOZED [ + label="STATE_OFF_AUTOMATIC_SNOOZED\nTurned off manually by the user." + + " The system should not turn it back on automatically." + ] + STATE_PENDING_STICKY_ON [ + label="STATE_PENDING_STICKY_ON\n" + + " Turned on manually by the user and then plugged in. Will turn back on after unplug." + ] + + STATE_OFF -> STATE_MANUAL_ON [label="manual"] + STATE_OFF -> STATE_AUTOMATIC_ON [label="Auto on AND charge <= auto threshold"] + + STATE_MANUAL_ON -> STATE_OFF [label="manual\nOR\nPlugged & sticky disabled"] + STATE_MANUAL_ON -> STATE_PENDING_STICKY_ON [label="Plugged & sticky enabled"] + + STATE_PENDING_STICKY_ON -> STATE_MANUAL_ON [label="Unplugged & sticky enabled"] + STATE_PENDING_STICKY_ON -> STATE_OFF [ + label="Sticky disabled\nOR\nSticky auto off enabled AND charge >= sticky auto off threshold" + ] + + STATE_AUTOMATIC_ON -> STATE_OFF [label="Plugged"] + STATE_AUTOMATIC_ON -> STATE_OFF_AUTOMATIC_SNOOZED [label="Manual"] + + STATE_OFF_AUTOMATIC_SNOOZED -> STATE_OFF [label="Plug\nOR\nCharge > auto threshold"] + STATE_OFF_AUTOMATIC_SNOOZED -> STATE_MANUAL_ON [label="manual"] + + </pre> + } */ public class BatterySaverStateMachine { private static final String TAG = "BatterySaverStateMachine"; @@ -60,6 +98,25 @@ public class BatterySaverStateMachine { private static final long ADAPTIVE_CHANGE_TIMEOUT_MS = 24 * 60 * 60 * 1000L; + /** Turn off adaptive battery saver if the device has charged above this level. */ + private static final int ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL = 80; + + private static final int STATE_OFF = BatterySaverStateMachineProto.STATE_OFF; + + /** Turned on manually by the user. */ + private static final int STATE_MANUAL_ON = BatterySaverStateMachineProto.STATE_MANUAL_ON; + + /** Turned on automatically by the system. */ + private static final int STATE_AUTOMATIC_ON = BatterySaverStateMachineProto.STATE_AUTOMATIC_ON; + + /** Turned off manually by the user. The system should not turn it back on automatically. */ + private static final int STATE_OFF_AUTOMATIC_SNOOZED = + BatterySaverStateMachineProto.STATE_OFF_AUTOMATIC_SNOOZED; + + /** Turned on manually by the user and then plugged in. Will turn back on after unplug. */ + private static final int STATE_PENDING_STICKY_ON = + BatterySaverStateMachineProto.STATE_PENDING_STICKY_ON; + private final Context mContext; private final BatterySaverController mBatterySaverController; @@ -75,6 +132,9 @@ public class BatterySaverStateMachine { @GuardedBy("mLock") private boolean mBatteryStatusSet; + @GuardedBy("mLock") + private int mState; + /** Whether the device is connected to any power source. */ @GuardedBy("mLock") private boolean mIsPowered; @@ -142,13 +202,6 @@ public class BatterySaverStateMachine { private boolean mDynamicPowerSavingsBatterySaver; /** - * Whether BS has been manually disabled while the battery level is low, in which case we - * shouldn't auto re-enable it until the battery level is not low. - */ - @GuardedBy("mLock") - private boolean mBatterySaverSnoozing; - - /** * Last reason passed to {@link #enableBatterySaverLocked}. */ @GuardedBy("mLock") @@ -181,6 +234,7 @@ public class BatterySaverStateMachine { mLock = lock; mContext = context; mBatterySaverController = batterySaverController; + mState = STATE_OFF; mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled); @@ -188,8 +242,36 @@ public class BatterySaverStateMachine { com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold); } - private boolean isAutoBatterySaverConfiguredLocked() { - return mSettingBatterySaverTriggerThreshold > 0; + /** @return true if the automatic percentage based mode should be used */ + private boolean isAutomaticModeActiveLocked() { + return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE + && mSettingBatterySaverTriggerThreshold > 0; + } + + /** + * The returned value won't necessarily make sense if {@link #isAutomaticModeActiveLocked()} + * returns {@code false}. + * + * @return true if the battery level is below automatic's threshold. + */ + private boolean isInAutomaticLowZoneLocked() { + return mIsBatteryLevelLow; + } + + /** @return true if the dynamic mode should be used */ + private boolean isDynamicModeActiveLocked() { + return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC + && mDynamicPowerSavingsBatterySaver; + } + + /** + * The returned value won't necessarily make sense if {@link #isDynamicModeActiveLocked()} + * returns {@code false}. + * + * @return true if the battery level is below dynamic's threshold. + */ + private boolean isInDynamicLowZoneLocked() { + return mBatteryLevel <= mDynamicPowerSavingsDisableThreshold; } /** @@ -233,7 +315,14 @@ public class BatterySaverStateMachine { Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL), false, mSettingsObserver, UserHandle.USER_SYSTEM); + synchronized (mLock) { + final boolean lowPowerModeEnabledSticky = getGlobalSetting( + Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0; + + if (lowPowerModeEnabledSticky) { + mState = STATE_PENDING_STICKY_ON; + } mBootCompleted = true; @@ -362,6 +451,8 @@ public class BatterySaverStateMachine { ? "Global.low_power changed to 1" : "Global.low_power changed to 0"; enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true, BatterySaverController.REASON_SETTING_CHANGED, reason); + } else { + doAutoBatterySaverLocked(); } } @@ -428,17 +519,6 @@ public class BatterySaverStateMachine { } } - @GuardedBy("mLock") - private boolean isBatteryLowLocked() { - final boolean percentageLow = - mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE - && mIsBatteryLevelLow; - final boolean dynamicPowerSavingsLow = - mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC - && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold; - return percentageLow || dynamicPowerSavingsLow; - } - /** * Decide whether to auto-start / stop battery saver. */ @@ -449,7 +529,6 @@ public class BatterySaverStateMachine { + " mSettingsLoaded=" + mSettingsLoaded + " mBatteryStatusSet=" + mBatteryStatusSet + " mIsBatteryLevelLow=" + mIsBatteryLevelLow - + " mBatterySaverSnoozing=" + mBatterySaverSnoozing + " mIsPowered=" + mIsPowered + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky @@ -460,66 +539,166 @@ public class BatterySaverStateMachine { return; // Not fully initialized yet. } - if (!isBatteryLowLocked()) { - updateSnoozingLocked(false, "Battery not low"); - } + updateStateLocked(false, false); + // Adaptive control. if (SystemClock.elapsedRealtime() - mLastAdaptiveBatterySaverChangedExternallyElapsed > ADAPTIVE_CHANGE_TIMEOUT_MS) { mBatterySaverController.setAdaptivePolicyEnabledLocked( false, BatterySaverController.REASON_TIMEOUT); mBatterySaverController.resetAdaptivePolicyLocked( BatterySaverController.REASON_TIMEOUT); + } else if (mIsPowered && mBatteryLevel >= ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL) { + mBatterySaverController.setAdaptivePolicyEnabledLocked(false, + BatterySaverController.REASON_PLUGGED_IN); + } + } + + /** + * Update the state machine based on the current settings and battery/charge status. + * + * @param manual Whether the change was made by the user. + * @param enable Whether the user wants to turn battery saver on or off. Is only used if {@param + * manual} is true. + */ + @GuardedBy("mLock") + private void updateStateLocked(boolean manual, boolean enable) { + if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) { + return; // Not fully initialized yet. } - if (mIsPowered) { - updateSnoozingLocked(false, "Plugged in"); - enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, - BatterySaverController.REASON_PLUGGED_IN, - "Plugged in"); + switch (mState) { + case STATE_OFF: { + if (!mIsPowered) { + if (manual) { + if (!enable) { + Slog.e(TAG, "Tried to disable BS when it's already OFF"); + return; + } + enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, + BatterySaverController.REASON_MANUAL_ON); + mState = STATE_MANUAL_ON; + } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) { + enableBatterySaverLocked(/*enable*/ true, /*manual*/ false, + BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON); + mState = STATE_AUTOMATIC_ON; + } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) { + enableBatterySaverLocked(/*enable*/ true, /*manual*/ false, + BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON); + mState = STATE_AUTOMATIC_ON; + } + } + break; + } - if (mBatteryLevel >= 80 /* Arbitrary level */) { - mBatterySaverController.setAdaptivePolicyEnabledLocked( - false, BatterySaverController.REASON_PLUGGED_IN); + case STATE_MANUAL_ON: { + if (manual) { + if (enable) { + Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON"); + return; + } + enableBatterySaverLocked(/*enable*/ false, /*manual*/ true, + BatterySaverController.REASON_MANUAL_OFF); + mState = STATE_OFF; + } else if (mIsPowered) { + enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, + BatterySaverController.REASON_PLUGGED_IN); + if (mSettingBatterySaverEnabledSticky + && !mBatterySaverStickyBehaviourDisabled) { + mState = STATE_PENDING_STICKY_ON; + } else { + mState = STATE_OFF; + } + } + break; } - } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) { - if (mSettingBatterySaverStickyAutoDisableEnabled - && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold) { - setStickyActive(false); - } else { - // Re-enable BS. - enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true, - BatterySaverController.REASON_STICKY_RESTORE, - "Sticky restore"); + case STATE_AUTOMATIC_ON: { + if (mIsPowered) { + enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, + BatterySaverController.REASON_PLUGGED_IN); + mState = STATE_OFF; + } else if (manual) { + if (enable) { + Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON"); + return; + } + enableBatterySaverLocked(/*enable*/ false, /*manual*/ true, + BatterySaverController.REASON_MANUAL_OFF); + // When battery saver is disabled manually (while battery saver is enabled) + // when the battery level is low, we "snooze" BS -- i.e. disable auto battery + // saver. + // We resume auto-BS once the battery level is not low, or the device is + // plugged in. + mState = STATE_OFF_AUTOMATIC_SNOOZED; + } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) { + enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, + BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF); + mState = STATE_OFF; + } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) { + enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, + BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF); + mState = STATE_OFF; + } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) { + enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, + BatterySaverController.REASON_SETTING_CHANGED); + mState = STATE_OFF; + } + break; } - } else if (mSettingAutomaticBatterySaver - == PowerManager.POWER_SAVER_MODE_PERCENTAGE - && isAutoBatterySaverConfiguredLocked()) { - if (mIsBatteryLevelLow && !mBatterySaverSnoozing) { - enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, - BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON, - "Percentage Auto ON"); - } else { - // Battery not low - enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, - BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF, - "Percentage Auto OFF"); + case STATE_OFF_AUTOMATIC_SNOOZED: { + if (manual) { + if (!enable) { + Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED"); + return; + } + enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, + BatterySaverController.REASON_MANUAL_ON); + mState = STATE_MANUAL_ON; + } else if (mIsPowered // Plugging in resets snooze. + || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) + || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) + || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) { + mState = STATE_OFF; + } + break; } - } else if (mSettingAutomaticBatterySaver - == PowerManager.POWER_SAVER_MODE_DYNAMIC) { - if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) { - enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, - BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF, - "Dynamic Warning Auto OFF"); - } else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) { - enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, - BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON, - "Dynamic Warning Auto ON"); + + case STATE_PENDING_STICKY_ON: { + if (manual) { + // This shouldn't be possible. We'll only be in this state when the device is + // plugged in, so the user shouldn't be able to manually change state. + Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON"); + return; + } + final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled + && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold; + final boolean isStickyDisabled = + mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky; + if (isStickyDisabled || shouldTurnOffSticky) { + setStickyActive(false); + mState = STATE_OFF; + } else if (!mIsPowered) { + // Re-enable BS. + enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, + BatterySaverController.REASON_STICKY_RESTORE); + mState = STATE_MANUAL_ON; + } + break; } + + default: + Slog.wtf(TAG, "Unknown state: " + mState); + break; + } + } + + @VisibleForTesting + int getState() { + synchronized (mLock) { + return mState; } - // do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0% } /** @@ -533,13 +712,17 @@ public class BatterySaverStateMachine { Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled); } synchronized (mLock) { - enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true, - (enabled ? BatterySaverController.REASON_MANUAL_ON - : BatterySaverController.REASON_MANUAL_OFF), - (enabled ? "Manual ON" : "Manual OFF")); + updateStateLocked(true, enabled); + // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and + // enabled is false } } + @GuardedBy("mLock") + private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) { + enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason)); + } + /** * Actually enable / disable battery saver. Write the new state to the global settings * and propagate it to {@link #mBatterySaverController}. @@ -566,20 +749,6 @@ public class BatterySaverStateMachine { mLastChangedIntReason = intReason; mLastChangedStrReason = strReason; - if (manual) { - if (enable) { - updateSnoozingLocked(false, "Manual snooze OFF"); - } else { - // When battery saver is disabled manually (while battery saver is enabled) - // when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver. - // We resume auto-BS once the battery level is not low, or the device is plugged in. - if (mBatterySaverController.isFullEnabled() && isBatteryLowLocked()) { - updateSnoozingLocked(true, "Manual snooze"); - } - // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true - } - } - mSettingBatterySaverEnabled = enable; putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0); @@ -641,15 +810,6 @@ public class BatterySaverStateMachine { manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID); } - @GuardedBy("mLock") - private void updateSnoozingLocked(boolean snoozing, String reason) { - if (mBatterySaverSnoozing == snoozing) { - return; - } - if (DEBUG) Slog.d(TAG, "Snooze: " + (snoozing ? "start" : "stop") + " reason=" + reason); - mBatterySaverSnoozing = snoozing; - } - private void setStickyActive(boolean active) { mSettingBatterySaverEnabledSticky = active; putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY, @@ -684,6 +844,8 @@ public class BatterySaverStateMachine { pw.print(")"); } pw.println(); + pw.print(" mState="); + pw.println(mState); pw.print(" mLastChangedIntReason="); pw.println(mLastChangedIntReason); @@ -697,9 +859,6 @@ public class BatterySaverStateMachine { pw.print(" mBatteryStatusSet="); pw.println(mBatteryStatusSet); - pw.print(" mBatterySaverSnoozing="); - pw.println(mBatterySaverSnoozing); - pw.print(" mIsPowered="); pw.println(mIsPowered); pw.print(" mBatteryLevel="); @@ -731,6 +890,7 @@ public class BatterySaverStateMachine { proto.write(BatterySaverStateMachineProto.ENABLED, mBatterySaverController.isEnabled()); + proto.write(BatterySaverStateMachineProto.STATE, mState); proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED, mBatterySaverController.isFullEnabled()); proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED, @@ -742,8 +902,6 @@ public class BatterySaverStateMachine { proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded); proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet); - proto.write(BatterySaverStateMachineProto.BATTERY_SAVER_SNOOZING, - mBatterySaverSnoozing); proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered); proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel); diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 83d18a6a5e15..d6327494a24d 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -16,6 +16,7 @@ package com.android.server.rollback; +import android.Manifest; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.BroadcastReceiver; @@ -24,6 +25,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.ApplicationInfo; +import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; @@ -42,6 +44,7 @@ import android.os.HandlerThread; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.DeviceConfig; import android.util.IntArray; import android.util.Log; @@ -220,9 +223,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override public ParceledListSlice getAvailableRollbacks() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ROLLBACKS, - "getAvailableRollbacks"); + enforceManageRollbacks("getAvailableRollbacks"); synchronized (mLock) { ensureRollbackDataLoadedLocked(); @@ -239,9 +240,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ROLLBACKS, - "getRecentlyExecutedRollbacks"); + enforceManageRollbacks("getRecentlyCommittedRollbacks"); synchronized (mLock) { ensureRollbackDataLoadedLocked(); @@ -259,9 +258,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override public void commitRollback(int rollbackId, ParceledListSlice causePackages, String callerPackageName, IntentSender statusReceiver) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ROLLBACKS, - "executeRollback"); + enforceManageRollbacks("executeRollback"); final int callingUid = Binder.getCallingUid(); AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); @@ -459,11 +456,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED); - // TODO: This call emits the warning "Calling a method in the - // system process without a qualified user". Fix that. - // TODO: Limit this to receivers holding the - // MANAGE_ROLLBACKS permission? - mContext.sendBroadcast(broadcast); + mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM, + Manifest.permission.MANAGE_ROLLBACKS); }); } ); @@ -484,7 +478,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override public void reloadPersistedData() { mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.TEST_MANAGE_ROLLBACKS, "reloadPersistedData"); synchronized (mLock) { @@ -499,7 +493,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override public void expireRollbackForPackage(String packageName) { mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.TEST_MANAGE_ROLLBACKS, "expireRollbackForPackage"); synchronized (mLock) { ensureRollbackDataLoadedLocked(); @@ -535,8 +529,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private void updateRollbackLifetimeDurationInMillis() { mRollbackLifetimeDurationInMillis = DeviceConfig.getLong( - DeviceConfig.Rollback.BOOT_NAMESPACE, - DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, + DeviceConfig.NAMESPACE_ROLLBACK_BOOT, + RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS, DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS); if (mRollbackLifetimeDurationInMillis < 0) { mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS; @@ -894,12 +888,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Log.i(TAG, "Enabling rollback for install of " + packageName + ", session:" + session.sessionId); + String installerPackageName = session.getInstallerPackageName(); + if (!enableRollbackAllowed(installerPackageName, packageName)) { + Log.e(TAG, "Installer " + installerPackageName + + " is not allowed to enable rollback on " + packageName); + return false; + } + VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode); final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0); // Get information about the currently installed package. PackageManager pm = mContext.getPackageManager(); - PackageInfo pkgInfo = null; + final PackageInfo pkgInfo; try { pkgInfo = pm.getPackageInfo(packageName, isApex ? PackageManager.MATCH_APEX : 0); } catch (PackageManager.NameNotFoundException e) { @@ -1086,6 +1087,44 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } /** + * Returns true if the installer is allowed to enable rollback for the + * given named package, false otherwise. + */ + private boolean enableRollbackAllowed(String installerPackageName, String packageName) { + if (installerPackageName == null) { + return false; + } + + PackageManager pm = mContext.getPackageManager(); + boolean manageRollbacksGranted = pm.checkPermission( + Manifest.permission.MANAGE_ROLLBACKS, + installerPackageName) == PackageManager.PERMISSION_GRANTED; + + boolean testManageRollbacksGranted = pm.checkPermission( + Manifest.permission.TEST_MANAGE_ROLLBACKS, + installerPackageName) == PackageManager.PERMISSION_GRANTED; + + // For now only allow rollbacks for modules or for testing. + return (isModule(packageName) && manageRollbacksGranted) + || testManageRollbacksGranted; + } + + /** + * Returns true if the package name is the name of a module. + */ + private boolean isModule(String packageName) { + PackageManager pm = mContext.getPackageManager(); + final ModuleInfo moduleInfo; + try { + moduleInfo = pm.getModuleInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + + return moduleInfo != null; + } + + /** * Gets the version of the package currently installed. * Returns null if the package is not currently installed. */ @@ -1311,4 +1350,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } } } + + private void enforceManageRollbacks(@NonNull String message) { + if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission( + Manifest.permission.MANAGE_ROLLBACKS)) + && (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission( + Manifest.permission.TEST_MANAGE_ROLLBACKS))) { + throw new SecurityException(message + " requires " + + Manifest.permission.MANAGE_ROLLBACKS + " or " + + Manifest.permission.TEST_MANAGE_ROLLBACKS); + } + } } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 2b17d19e1cf7..18004336e7a2 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -19,6 +19,8 @@ import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.os.Process.getPidsForCommands; import static android.os.Process.getUidForPid; +import static android.os.storage.VolumeInfo.TYPE_PRIVATE; +import static android.os.storage.VolumeInfo.TYPE_PUBLIC; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs; @@ -89,6 +91,7 @@ import android.os.UserManager; import android.os.storage.DiskInfo; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import android.stats.storage.StorageEnums; import android.telephony.ModemActivityInfo; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -1968,7 +1971,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } - private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos, + private void pullExternalStorageInfo(int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { StorageManager storageManager = mContext.getSystemService(StorageManager.class); if (storageManager != null) { @@ -1976,11 +1979,29 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { for (VolumeInfo vol : volumes) { final String envState = VolumeInfo.getEnvironmentForState(vol.getState()); final DiskInfo diskInfo = vol.getDisk(); - if (diskInfo != null && diskInfo.isSd()) { + if (diskInfo != null) { if (envState.equals(Environment.MEDIA_MOUNTED)) { + // Get the type of the volume, if it is adoptable or portable. + int volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__OTHER; + if (vol.getType() == TYPE_PUBLIC) { + volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PUBLIC; + } else if (vol.getType() == TYPE_PRIVATE) { + volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PRIVATE; + } + // Get the type of external storage inserted in the device (sd cards, + // usb, etc) + int externalStorageType; + if (diskInfo.isSd()) { + externalStorageType = StorageEnums.SD_CARD; + } else if (diskInfo.isUsb()) { + externalStorageType = StorageEnums.USB; + } else { + externalStorageType = StorageEnums.OTHER; + } StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(vol.getType() + 1); + e.writeInt(externalStorageType); + e.writeInt(volumeType); e.writeLong(diskInfo.size); pulledData.add(e); } @@ -2185,8 +2206,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret); break; } - case StatsLog.SDCARD_INFO: { - pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret); + case StatsLog.EXTERNAL_STORAGE_INFO: { + pullExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret); break; } default: diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index a33b454d51dc..9d6efb4f76cb 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -1173,7 +1173,17 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } private void releaseSelfIfNeeded() { - if (mStacks.isEmpty() && mRemoved) { + if (!mRemoved || mDisplayContent == null) { + return; + } + + final ActivityStack stack = mStacks.size() == 1 ? mStacks.get(0) : null; + if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) { + // Release this display if an empty home stack is the only thing left. + // Since it is the last stack, this display will be released along with the stack + // removal. + stack.remove(); + } else if (mStacks.isEmpty()) { mDisplayContent.removeIfPossible(); mDisplayContent = null; mRootActivityContainer.removeChild(this); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index ad989704b823..4c9b80be5d7c 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -3053,7 +3053,17 @@ class ActivityStack extends ConfigurationContainer { ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityInNextFocusableStack: " + reason + ", go home"); - return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId); + if (isActivityTypeHome()) { + // resumeTopActivityUncheckedLocked has been prevented to run recursively. Post a + // runnable to resume home since we are currently in the process of resuming top + // activity in home stack. + // See {@link #mInResumeTopActivity}. + mService.mH.post( + () -> mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId)); + return true; + } else { + return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId); + } } /** Returns the position the input task should be placed in this stack. */ diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 5a20959dcdbf..b262a006a545 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -352,6 +352,19 @@ public abstract class ActivityTaskManagerInternal { /** @return The intent used to launch the home activity. */ public abstract Intent getHomeIntent(); public abstract boolean startHomeActivity(int userId, String reason); + /** + * This starts home activity on displays that can have system decorations based on displayId - + * Default display always use primary home component. + * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves + * according to the priorities listed below. + * - If default home is not set, always use the secondary home defined in the config. + * - Use currently selected primary home activity. + * - Use the activity in the same package as currently selected primary home activity. + * If there are multiple activities matched, use first one. + * - Use the secondary home defined in the config. + */ + public abstract boolean startHomeOnDisplay(int userId, String reason, int displayId, + boolean fromHomeKey); /** Start home activities on all displays that support system decorations. */ public abstract boolean startHomeOnAllDisplays(int userId, String reason); /** @return true if the given process is the factory test process. */ diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index a1dbbab2036a..118eb5bea602 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -6491,6 +6491,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public boolean startHomeOnDisplay(int userId, String reason, int displayId, + boolean fromHomeKey) { + return mRootActivityContainer.startHomeOnDisplay(userId, reason, displayId, + fromHomeKey); + } + + @Override public boolean startHomeOnAllDisplays(int userId, String reason) { synchronized (mGlobalLock) { return mRootActivityContainer.startHomeOnAllDisplays(userId, reason); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b00cafdccf11..bec72f5686df 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -130,6 +130,7 @@ import static com.android.server.wm.WindowManagerService.logSurface; import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; +import static com.android.server.wm.utils.RegionUtils.rectListToRegion; import android.animation.AnimationHandler; import android.annotation.CallSuper; @@ -153,6 +154,7 @@ import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -165,6 +167,7 @@ import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.Gravity; +import android.view.ISystemGestureExclusionListener; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputWindowHandle; @@ -312,6 +315,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private DisplayRotation mDisplayRotation; DisplayFrames mDisplayFrames; + private final RemoteCallbackList<ISystemGestureExclusionListener> + mSystemGestureExclusionListeners = new RemoteCallbackList<>(); + private final Region mSystemGestureExclusion = new Region(); + /** * For default display it contains real metrics, empty for others. * @see WindowManagerService#createWatermarkInTransaction() @@ -2818,6 +2825,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mWallpaperController.dump(pw, " "); pw.println(); + pw.print("mSystemGestureExclusion="); + if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) { + pw.println(mSystemGestureExclusion); + } else { + pw.println("<no lstnrs>"); + } + + pw.println(); pw.println(prefix + "Application tokens in top down Z order:"); for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); @@ -4951,6 +4966,100 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } /** + * Updates the display's system gesture exclusion. + * + * @return true, if the exclusion changed. + */ + boolean updateSystemGestureExclusion() { + if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 0) { + // No one's interested anyways. + return false; + } + + final Region systemGestureExclusion = calculateSystemGestureExclusion(); + try { + if (mSystemGestureExclusion.equals(systemGestureExclusion)) { + return false; + } + mSystemGestureExclusion.set(systemGestureExclusion); + for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) { + try { + mSystemGestureExclusionListeners.getBroadcastItem(i) + .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e); + } + } + mSystemGestureExclusionListeners.finishBroadcast(); + return true; + } finally { + systemGestureExclusion.recycle(); + } + } + + @VisibleForTesting + Region calculateSystemGestureExclusion() { + final Region global = Region.obtain(); + final Region touchableRegion = Region.obtain(); + final Region local = Region.obtain(); + + // Traverse all windows bottom up to assemble the gesture exclusion rects. + // For each window, we only take the rects that fall within its touchable region. + forAllWindows(w -> { + if (w.cantReceiveTouchInput() || !w.isVisible() + || (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0) { + return; + } + final boolean modal = + (w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; + + // Only keep the exclusion zones from the windows behind where the current window + // isn't touchable. + w.getTouchableRegion(touchableRegion); + global.op(touchableRegion, Op.DIFFERENCE); + + rectListToRegion(w.getSystemGestureExclusion(), local); + + // Transform to display coordinates + local.scale(w.mGlobalScale); + final Rect frame = w.getWindowFrames().mFrame; + local.translate(frame.left, frame.top); + + // A window can only exclude system gestures where it is actually touchable + local.op(touchableRegion, Op.INTERSECT); + + global.op(local, Op.UNION); + }, false /* topToBottom */); + local.recycle(); + touchableRegion.recycle(); + return global; + } + + void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener) { + mSystemGestureExclusionListeners.register(listener); + final boolean changed; + if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 1) { + changed = updateSystemGestureExclusion(); + } else { + changed = false; + } + + if (!changed) { + // If updateSystemGestureExclusion changed the exclusion, it will already have + // notified the listener. Otherwise, we'll do it here. + try { + listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e); + } + } + } + + void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener) { + mSystemGestureExclusionListeners.unregister(listener); + } + + /** * Create a portal window handle for input. This window transports any touch to the display * indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window. * diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 8c8b05f1307a..72a1a2f0cac2 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -269,7 +269,8 @@ class KeyguardController { * @return True if we may show an activity while Keyguard is occluded, false otherwise. */ boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) { - return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure(); + return showWhenLocked || dismissKeyguard + && !mWindowManager.isKeyguardSecure(mService.getCurrentUserId()); } private void visibilitiesUpdated() { @@ -317,7 +318,7 @@ class KeyguardController { // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded. - if (!mWindowManager.isKeyguardSecure()) { + if (!mWindowManager.isKeyguardSecure(mService.getCurrentUserId())) { return; } @@ -345,7 +346,8 @@ class KeyguardController { * @return true if Keyguard can be currently dismissed without entering credentials. */ boolean canDismissKeyguard() { - return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure(); + return mWindowManager.isKeyguardTrusted() + || !mWindowManager.isKeyguardSecure(mService.getCurrentUserId()); } private int resolveOccludeTransit() { @@ -487,7 +489,8 @@ class KeyguardController { } if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded && mDismissingKeyguardActivity != null - && controller.mWindowManager.isKeyguardSecure()) { + && controller.mWindowManager.isKeyguardSecure( + controller.mService.getCurrentUserId())) { mRequestDismissKeyguard = true; } } diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index e6e6275feacd..2411e006a562 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -762,7 +762,7 @@ public class LockTaskController { } else { // If keyguard is not secure and it is locked, dismiss the keyguard before // disabling it, which avoids the platform to think the keyguard is still on. - if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure()) { + if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure(userId)) { mPendingDisableFromDismiss = userId; mWindowManager.dismissKeyguard(new IKeyguardDismissCallback.Stub() { @Override diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index f964b5753488..24cf7f127e18 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -114,6 +114,7 @@ import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; import com.android.server.am.AppTimeTracker; import com.android.server.am.UserState; +import com.android.server.policy.WindowManagerPolicy; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -345,6 +346,10 @@ class RootActivityContainer extends ConfigurationContainer } } + boolean startHomeOnDisplay(int userId, String reason, int displayId) { + return startHomeOnDisplay(userId, reason, displayId, false /*fromHomeKey*/); + } + /** * This starts home activity on displays that can have system decorations based on displayId - * Default display always use primary home component. @@ -356,7 +361,12 @@ class RootActivityContainer extends ConfigurationContainer * If there are multiple activities matched, use first one. * - Use the secondary home defined in the config. */ - boolean startHomeOnDisplay(int userId, String reason, int displayId) { + boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean fromHomeKey) { + // Fallback to top focused display if the displayId is invalid. + if (displayId == INVALID_DISPLAY) { + displayId = getTopDisplayFocusedStack().mDisplayId; + } + Intent homeIntent; ActivityInfo aInfo; if (displayId == DEFAULT_DISPLAY) { @@ -380,6 +390,10 @@ class RootActivityContainer extends ConfigurationContainer // Updates the home component of the intent. homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK); + // Updates the extra information of the intent. + if (fromHomeKey) { + homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true); + } // Update the reason for ANR debugging to verify if the user activity is the one that // actually launched. final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId( diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 8f4e8422581b..ed5f6658197b 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -682,6 +682,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Finally update all input windows now that the window changes have stabilized. forAllDisplays(dc -> { dc.getInputMonitor().updateInputWindowsLw(true /*force*/); + dc.updateSystemGestureExclusion(); }); mWmService.setHoldScreenLocked(mHoldScreen); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index dc8c7b79feef..9b634f959fca 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -57,6 +57,7 @@ import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.function.BiConsumer; @@ -314,6 +315,16 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } } + @Override + public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) { + long ident = Binder.clearCallingIdentity(); + try { + mService.reportSystemGestureExclusionChanged(this, window, exclusionRects); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void actionOnWallpaper(IBinder window, BiConsumer<WallpaperController, WindowState> action) { final WindowState windowState = mService.windowForClientLocked(this, window, true); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a6c92571bc03..7751560203e7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -202,6 +202,7 @@ import android.view.IOnKeyguardExitResult; import android.view.IPinnedStackListener; import android.view.IRecentsAnimationRunner; import android.view.IRotationWatcher; +import android.view.ISystemGestureExclusionListener; import android.view.IWallpaperVisibilityListener; import android.view.IWindow; import android.view.IWindowId; @@ -274,6 +275,7 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.List; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub @@ -2868,8 +2870,13 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public boolean isKeyguardSecure() { - int userId = UserHandle.getCallingUserId(); + public boolean isKeyguardSecure(int userId) { + if (userId != UserHandle.getCallingUserId() + && !checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS, + "isKeyguardSecure")) { + throw new SecurityException("Requires INTERACT_ACROSS_USERS permission"); + } + long origId = Binder.clearCallingIdentity(); try { return mPolicy.isKeyguardSecure(userId); @@ -3812,6 +3819,42 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId) { + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + throw new IllegalArgumentException("Trying to register visibility event " + + "for invalid display: " + displayId); + } + displayContent.registerSystemGestureExclusionListener(listener); + } + } + + @Override + public void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener, + int displayId) { + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + throw new IllegalArgumentException("Trying to register visibility event " + + "for invalid display: " + displayId); + } + displayContent.unregisterSystemGestureExclusionListener(listener); + } + } + + void reportSystemGestureExclusionChanged(Session session, IWindow window, + List<Rect> exclusionRects) { + synchronized (mGlobalLock) { + final WindowState win = windowForClientLocked(session, window, true); + if (win.setSystemGestureExclusion(exclusionRects)) { + win.getDisplayContent().updateSystemGestureExclusion(); + } + } + } + + @Override public void registerDisplayFoldListener(IDisplayFoldListener listener) { mPolicy.registerDisplayFoldListener(listener); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ee445d836214..600178fa3276 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -205,6 +205,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.function.Predicate; /** A window in the window manager. */ @@ -363,6 +364,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private final Rect mInsetFrame = new Rect(); + /** + * List of rects where system gestures should be ignored. + * + * Coordinates are relative to the window's position. + */ + private final List<Rect> mExclusionRects = new ArrayList<>(); + // If a window showing a wallpaper: the requested offset for the // wallpaper; if a wallpaper window: the currently applied offset. float mWallpaperX = -1; @@ -612,6 +620,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + List<Rect> getSystemGestureExclusion() { + return mExclusionRects; + } + + /** + * Sets the system gesture exclusion rects. + * + * @return {@code true} if anything changed + */ + boolean setSystemGestureExclusion(List<Rect> exclusionRects) { + if (mExclusionRects.equals(exclusionRects)) { + return false; + } + mExclusionRects.clear(); + mExclusionRects.addAll(exclusionRects); + return true; + } + interface PowerManagerWrapper { void wakeUp(long time, @WakeReason int reason, String details); diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java new file mode 100644 index 000000000000..1458440f7b81 --- /dev/null +++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.utils; + +import android.graphics.Rect; +import android.graphics.Region; + +import java.util.List; + +/** + * Utility methods to handle Regions. + */ +public class RegionUtils { + + private RegionUtils() {} + + + /** + * Converts a list of rects into a {@code Region}. + * + * @param rects the list of rects to convert + * @param outRegion the Region to set to the list of rects + */ + public static void rectListToRegion(List<Rect> rects, Region outRegion) { + outRegion.setEmpty(); + final int n = rects.size(); + for (int i = 0; i < n; i++) { + outRegion.union(rects.get(i)); + } + } +} diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 050a07965b9c..00b815ae1bfa 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -109,6 +109,7 @@ cc_defaults { "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", "android.hardware.gnss@2.0", + "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.visibility_control@1.0", "android.hardware.input.classifier@1.0", "android.hardware.ir@1.0", diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index caba3afed41b..a6e9fdde7735 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -71,6 +71,7 @@ static jmethodID method_reportMeasurementData; static jmethodID method_reportNavigationMessages; static jmethodID method_reportLocationBatch; static jmethodID method_reportGnssServiceDied; +static jmethodID method_setMeasurementCorrectionsCapabilities; static jmethodID method_correctionsGetLatitudeDegrees; static jmethodID method_correctionsGetLongitudeDegrees; static jmethodID method_correctionsGetAltitudeMeters; @@ -118,7 +119,6 @@ using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V1_0::IAGnssRilCallback; using android::hardware::gnss::V1_0::IGnssBatching; using android::hardware::gnss::V1_0::IGnssBatchingCallback; -using android::hardware::gnss::V1_0::IGnssDebug; using android::hardware::gnss::V1_0::IGnssGeofenceCallback; using android::hardware::gnss::V1_0::IGnssGeofencing; using android::hardware::gnss::V1_0::IGnssNavigationMessage; @@ -142,9 +142,12 @@ using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation; using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss; using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss; using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss; +using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback; using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration; using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; +using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug; +using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug; using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; @@ -158,10 +161,9 @@ using IAGnss_V2_0 = android::hardware::gnss::V2_0::IAGnss; using IAGnssCallback_V1_0 = android::hardware::gnss::V1_0::IAGnssCallback; using IAGnssCallback_V2_0 = android::hardware::gnss::V2_0::IAGnssCallback; -using IMeasurementCorrections = - android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections; -using GnssSingleSatCorrectionFlags = - android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags; +using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections; +using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback; +using android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags; using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl; using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback; @@ -191,7 +193,8 @@ sp<IGnssGeofencing> gnssGeofencingIface = nullptr; sp<IAGnss_V1_0> agnssIface = nullptr; sp<IAGnss_V2_0> agnssIface_V2_0 = nullptr; sp<IGnssBatching> gnssBatchingIface = nullptr; -sp<IGnssDebug> gnssDebugIface = nullptr; +sp<IGnssDebug_V1_0> gnssDebugIface = nullptr; +sp<IGnssDebug_V2_0> gnssDebugIface_V2_0 = nullptr; sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr; sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr; sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr; @@ -201,7 +204,6 @@ sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr; sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr; sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr; sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr; - sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr; #define WAKE_LOCK_NAME "GPS" @@ -549,7 +551,9 @@ static GnssLocation_V2_0 createGnssLocation_V2_0( struct GnssCallback : public IGnssCallback { Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override; Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override; - Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; + Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override { + return gnssSvStatusCbImpl(svStatus); + } Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override; Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override; Return<void> gnssAcquireWakelockCb() override; @@ -567,14 +571,47 @@ struct GnssCallback : public IGnssCallback { override; Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override; Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override; + Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) override { + return gnssSvStatusCbImpl(svInfoList); + } - // Templated implementation for gnnsLocationCb and gnnsLocationCb_2_0. - template <class T> - Return<void> gnssLocationCbImpl(const T& location); + Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags); - // TODO(b/73306084): Reconsider allocation cost vs threadsafety on these statics + // TODO: Reconsider allocation cost vs threadsafety on these statics static const char* sNmeaString; static size_t sNmeaStringLength; +private: + template<class T> + Return<void> gnssLocationCbImpl(const T& location); + + template<class T> + Return<void> gnssSvStatusCbImpl(const T& svStatus); + + uint32_t getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) { + return svStatus.numSvs; + } + + uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) { + return svInfoList.size(); + } + + const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex( + const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) { + return svStatus.gnssSvList.data()[i]; + } + + const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex( + const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) { + return svInfoList[i].v1_0; + } + + uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) { + return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation); + } + + uint32_t getConstellationType(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) { + return static_cast<uint32_t>(svInfoList[i].constellation); + } }; Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) { @@ -622,10 +659,11 @@ Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue sta return Void(); } -Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) { +template<class T> +Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) { JNIEnv* env = getJniEnv(); - uint32_t listSize = svStatus.numSvs; + uint32_t listSize = getGnssSvInfoListSize(svStatus); if (listSize > static_cast<uint32_t>( android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) { ALOGD("Too many satellites %u. Clamps to %u.", listSize, @@ -654,9 +692,9 @@ Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svS CONSTELLATION_TYPE_SHIFT_WIDTH = 4 }; - const IGnssCallback::GnssSvInfo& info = svStatus.gnssSvList.data()[i]; + const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i); svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) | - (static_cast<uint32_t>(info.constellation) << CONSTELLATION_TYPE_SHIFT_WIDTH) | + (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) | static_cast<uint32_t>(info.svFlag); cn0s[i] = info.cN0Dbhz; elev[i] = info.elevationDegrees; @@ -694,18 +732,31 @@ Return<void> GnssCallback::gnssNmeaCb( } Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) { - ALOGD("%s: %du\n", __func__, capabilities); + return GnssCallback::gnssSetCapabilitesCbImpl(capabilities, + /* hasSubHalCapabilityFlags = */ true); +} +Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) { + return GnssCallback::gnssSetCapabilitesCbImpl(capabilities, + /* hasSubHalCapabilityFlags = */ false); +} + +Return <void> GnssCallback::gnssSetCapabilitesCbImpl(uint32_t capabilities, + bool hasSubHalCapabilityFlags) { + // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum + // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate + // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the + // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs + // which explicitly set the sub-HAL capability bits must continue to work. + ALOGD("%s: capabilities=%du, hasSubHalCapabilityFlags=%d\n", __func__, capabilities, + hasSubHalCapabilityFlags); JNIEnv* env = getJniEnv(); - env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities); + env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities, + boolToJbool(hasSubHalCapabilityFlags)); checkAndClearExceptionFromCallback(env, __FUNCTION__); return Void(); } -Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) { - return GnssCallback::gnssSetCapabilitesCb(capabilities); -} - Return<void> GnssCallback::gnssAcquireWakelockCb() { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); return Void(); @@ -1065,6 +1116,9 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated. SET(State, static_cast<int32_t>(measurement_V2_0->state)); + + // Overwrite with v2_0.constellation since v2_0->v1_1->v1_0.constellation is deprecated. + SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation)); } jobject GnssMeasurementCallback::translateGnssClock( @@ -1153,6 +1207,22 @@ void GnssMeasurementCallback::setMeasurementData(JNIEnv* env, jobject clock, } /* + * MeasurementCorrectionsCallback implements callback methods of interface + * IMeasurementCorrectionsCallback.hal. + */ +struct MeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback { + Return<void> setCapabilitiesCb(uint32_t capabilities) override; +}; + +Return<void> MeasurementCorrectionsCallback::setCapabilitiesCb(uint32_t capabilities) { + ALOGD("%s: %du\n", __func__, capabilities); + JNIEnv* env = getJniEnv(); + env->CallVoidMethod(mCallbacksObj, method_setMeasurementCorrectionsCapabilities, capabilities); + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return Void(); +} + +/* * GnssNiCallback implements callback methods required by the IGnssNi interface. */ struct GnssNiCallback : public IGnssNiCallback { @@ -1434,7 +1504,7 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V"); method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V"); method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); - method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); + method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(IZ)V"); method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V"); method_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName", "(Ljava/lang/String;)V"); @@ -1474,6 +1544,9 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass "(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V"); method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z"); + method_setMeasurementCorrectionsCapabilities = env->GetMethodID(clazz, + "setMeasurementCorrectionsCapabilities", "(I)V"); + jclass measCorrClass = env->FindClass("android/location/GnssMeasurementCorrections"); method_correctionsGetLatitudeDegrees = env->GetMethodID( measCorrClass,"getLatitudeDegrees", "()D"); @@ -1591,7 +1664,7 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass } if (gnssHal_V2_0 != nullptr) { - // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0 + // TODO: getExtensionGnssMeasurement_1_1 from gnssHal_V2_0 auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0(); if (!gnssMeasurement.isOk()) { ALOGD("Unable to get a handle to GnssMeasurement_V2_0"); @@ -1623,11 +1696,21 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass } } - auto gnssDebug = gnssHal->getExtensionGnssDebug(); - if (!gnssDebug.isOk()) { - ALOGD("Unable to get a handle to GnssDebug"); + if (gnssHal_V2_0 != nullptr) { + auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0(); + if (!gnssDebug.isOk()) { + ALOGD("Unable to get a handle to GnssDebug_V2_0"); + } else { + gnssDebugIface_V2_0 = gnssDebug; + gnssDebugIface = gnssDebugIface_V2_0; + } } else { - gnssDebugIface = gnssDebug; + auto gnssDebug = gnssHal->getExtensionGnssDebug(); + if (!gnssDebug.isOk()) { + ALOGD("Unable to get a handle to GnssDebug"); + } else { + gnssDebugIface = gnssDebug; + } } auto gnssNi = gnssHal->getExtensionGnssNi(); @@ -1795,6 +1878,12 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface); } + if (gnssCorrectionsIface != nullptr) { + sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface = + new MeasurementCorrectionsCallback(); + gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface); + } + return JNI_TRUE; } @@ -2150,76 +2239,100 @@ static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* en gnssNiIface->respond(notifId, static_cast<IGnssNiCallback::GnssUserResponseType>(response)); } +const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) { + return satelliteDataArray[i]; +} + +const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) { + return satelliteDataArray[i].v1_0; +} + +template<class T> +uint32_t getConstellationType(const hidl_vec<T>& satelliteDataArray, size_t i) { + return static_cast<uint32_t>(satelliteDataArray[i].constellation); +} + +template<class T> +static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, const T& data) { + internalState << "Gnss Location Data:: "; + if (!data.position.valid) { + internalState << "not valid"; + } else { + internalState << "LatitudeDegrees: " << data.position.latitudeDegrees + << ", LongitudeDegrees: " << data.position.longitudeDegrees + << ", altitudeMeters: " << data.position.altitudeMeters + << ", speedMetersPerSecond: " << data.position.speedMetersPerSec + << ", bearingDegrees: " << data.position.bearingDegrees + << ", horizontalAccuracyMeters: " + << data.position.horizontalAccuracyMeters + << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters + << ", speedAccuracyMetersPerSecond: " + << data.position.speedAccuracyMetersPerSecond + << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees + << ", ageSeconds: " << data.position.ageSeconds; + } + internalState << std::endl; + + internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate + << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs + << ", frequencyUncertaintyNsPerSec: " + << data.time.frequencyUncertaintyNsPerSec << std::endl; + + if (data.satelliteDataArray.size() != 0) { + internalState << "Satellite Data for " << data.satelliteDataArray.size() + << " satellites:: " << std::endl; + } + + internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; " + << "ephType: 0=Eph, 1=Alm, 2=Unk; " + << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; " + << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl; + for (size_t i = 0; i < data.satelliteDataArray.size(); i++) { + IGnssDebug_V1_0::SatelliteData satelliteData = + getSatelliteData(data.satelliteDataArray, i); + internalState << "constell: " + << getConstellationType(data.satelliteDataArray, i) + << ", svid: " << std::setw(3) << satelliteData.svid + << ", serverPredAvail: " + << satelliteData.serverPredictionIsAvailable + << ", serverPredAgeSec: " << std::setw(7) + << satelliteData.serverPredictionAgeSeconds + << ", ephType: " + << static_cast<uint32_t>(satelliteData.ephemerisType) + << ", ephSource: " + << static_cast<uint32_t>(satelliteData.ephemerisSource) + << ", ephHealth: " + << static_cast<uint32_t>(satelliteData.ephemerisHealth) + << ", ephAgeSec: " << std::setw(7) + << satelliteData.ephemerisAgeSeconds << std::endl; + } + return (jstring) env->NewStringUTF(internalState.str().c_str()); +} + static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env, jobject /* obj */) { jstring result = nullptr; /* - * TODO(b/33089503) : Create a jobject to represent GnssDebug. + * TODO: Create a jobject to represent GnssDebug. */ std::stringstream internalState; if (gnssDebugIface == nullptr) { internalState << "Gnss Debug Interface not available" << std::endl; + } else if (gnssDebugIface_V2_0 != nullptr) { + IGnssDebug_V2_0::DebugData data; + gnssDebugIface_V2_0->getDebugData_2_0([&data](const IGnssDebug_V2_0::DebugData& debugData) { + data = debugData; + }); + result = parseDebugData(env, internalState, data); } else { - IGnssDebug::DebugData data; - gnssDebugIface->getDebugData([&data](const IGnssDebug::DebugData& debugData) { + IGnssDebug_V1_0::DebugData data; + gnssDebugIface->getDebugData([&data](const IGnssDebug_V1_0::DebugData& debugData) { data = debugData; }); - - internalState << "Gnss Location Data:: "; - if (!data.position.valid) { - internalState << "not valid"; - } else { - internalState << "LatitudeDegrees: " << data.position.latitudeDegrees - << ", LongitudeDegrees: " << data.position.longitudeDegrees - << ", altitudeMeters: " << data.position.altitudeMeters - << ", speedMetersPerSecond: " << data.position.speedMetersPerSec - << ", bearingDegrees: " << data.position.bearingDegrees - << ", horizontalAccuracyMeters: " - << data.position.horizontalAccuracyMeters - << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters - << ", speedAccuracyMetersPerSecond: " - << data.position.speedAccuracyMetersPerSecond - << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees - << ", ageSeconds: " << data.position.ageSeconds; - } - internalState << std::endl; - - internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate - << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs - << ", frequencyUncertaintyNsPerSec: " - << data.time.frequencyUncertaintyNsPerSec << std::endl; - - if (data.satelliteDataArray.size() != 0) { - internalState << "Satellite Data for " << data.satelliteDataArray.size() - << " satellites:: " << std::endl; - } - - internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL; " - << "ephType: 0=Eph, 1=Alm, 2=Unk; " - << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; " - << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl; - for (size_t i = 0; i < data.satelliteDataArray.size(); i++) { - internalState << "constell: " - << static_cast<uint32_t>(data.satelliteDataArray[i].constellation) - << ", svid: " << std::setw(3) << data.satelliteDataArray[i].svid - << ", serverPredAvail: " - << data.satelliteDataArray[i].serverPredictionIsAvailable - << ", serverPredAgeSec: " << std::setw(7) - << data.satelliteDataArray[i].serverPredictionAgeSeconds - << ", ephType: " - << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisType) - << ", ephSource: " - << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisSource) - << ", ephHealth: " - << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisHealth) - << ", ephAgeSec: " << std::setw(7) - << data.satelliteDataArray[i].ephemerisAgeSeconds << std::endl; - } + result = parseDebugData(env, internalState, data); } - - result = env->NewStringUTF(internalState.str().c_str()); return result; } @@ -2380,13 +2493,25 @@ static jboolean android_location_GnssMeasurementsProvider_stop_measurement_colle return boolToJbool(result.isOk()); } -static jboolean android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections( +static jboolean + android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported( + JNIEnv* env, jclass clazz) { + if (gnssCorrectionsIface != nullptr) { + return JNI_TRUE; + } + + return JNI_FALSE; +} + +static jboolean + android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections( JNIEnv* env, jobject obj /* clazz*/, jobject correctionsObj) { if (gnssCorrectionsIface == nullptr) { - ALOGW("Trying to inject GNSS corrections on a chipset that does not support them."); + ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not" + " support them."); return JNI_FALSE; } @@ -2882,18 +3007,25 @@ static const JNINativeMethod sGeofenceMethods[] = { static const JNINativeMethod sMeasurementMethods[] = { /* name, signature, funcPtr */ {"native_is_measurement_supported", "()Z", - reinterpret_cast<void*>( - android_location_GnssMeasurementsProvider_is_measurement_supported)}, + reinterpret_cast<void*>( + android_location_GnssMeasurementsProvider_is_measurement_supported)}, {"native_start_measurement_collection", "(Z)Z", - reinterpret_cast<void*>( - android_location_GnssMeasurementsProvider_start_measurement_collection)}, + reinterpret_cast<void*>( + android_location_GnssMeasurementsProvider_start_measurement_collection)}, {"native_stop_measurement_collection", "()Z", - reinterpret_cast<void*>( - android_location_GnssMeasurementsProvider_stop_measurement_collection)}, + reinterpret_cast<void*>( + android_location_GnssMeasurementsProvider_stop_measurement_collection)}, +}; + +static const JNINativeMethod sMeasurementCorrectionsMethods[] = { + /* name, signature, funcPtr */ + {"native_is_measurement_corrections_supported", "()Z", + reinterpret_cast<void*>( + android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)}, {"native_inject_gnss_measurement_corrections", - "(Landroid/location/GnssMeasurementCorrections;)Z", - reinterpret_cast<void*>( - android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections)}, + "(Landroid/location/GnssMeasurementCorrections;)Z", + reinterpret_cast<void*>( + android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)}, }; static const JNINativeMethod sNavigationMessageMethods[] = { @@ -2992,6 +3124,11 @@ int register_android_server_location_GnssLocationProvider(JNIEnv* env) { NELEM(sMeasurementMethods)); jniRegisterNativeMethods( env, + "com/android/server/location/GnssMeasurementCorrectionsProvider", + sMeasurementCorrectionsMethods, + NELEM(sMeasurementCorrectionsMethods)); + jniRegisterNativeMethods( + env, "com/android/server/location/GnssNavigationMessageProvider", sNavigationMessageMethods, NELEM(sNavigationMessageMethods)); diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp deleted file mode 100644 index 013cf5616904..000000000000 --- a/services/ipmemorystore/Android.bp +++ /dev/null @@ -1,4 +0,0 @@ -java_library_static { - name: "services.ipmemorystore", - srcs: ["java/**/*.java"], -} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3f323d98a303..419f52cff578 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -108,7 +108,6 @@ import com.android.server.media.MediaSessionService; import com.android.server.media.projection.MediaProjectionManagerService; import com.android.server.net.NetworkPolicyManagerService; import com.android.server.net.NetworkStatsService; -import com.android.server.net.ipmemorystore.IpMemoryStoreService; import com.android.server.net.watchlist.NetworkWatchlistService; import com.android.server.notification.NotificationManagerService; import com.android.server.oemlock.OemLockService; @@ -1231,6 +1230,7 @@ public final class SystemServer { } startContentCaptureService(context); + startAttentionService(context); // App prediction manager service traceBeginAndSlog("StartAppPredictionService"); @@ -1264,14 +1264,6 @@ public final class SystemServer { } traceEnd(); - traceBeginAndSlog("StartIpMemoryStoreService"); - try { - ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE, - new IpMemoryStoreService(context)); - } catch (Throwable e) { - reportWtf("starting IP Memory Store Service", e); - } - traceEnd(); traceBeginAndSlog("StartIpSecService"); try { @@ -1293,10 +1285,6 @@ public final class SystemServer { traceEnd(); } - traceBeginAndSlog("StartAttentionManagerService"); - mSystemServiceManager.startService(AttentionManagerService.class); - traceEnd(); - traceBeginAndSlog("StartNetworkScoreService"); mSystemServiceManager.startService(NetworkScoreService.Lifecycle.class); traceEnd(); @@ -2269,6 +2257,17 @@ public final class SystemServer { traceEnd(); } + private void startAttentionService(@NonNull Context context) { + if (!AttentionManagerService.isServiceConfigured(context)) { + Slog.d(TAG, "AttentionService is not configured on this device"); + return; + } + + traceBeginAndSlog("StartAttentionManagerService"); + mSystemServiceManager.startService(AttentionManagerService.class); + traceEnd(); + } + static final void startSystemUi(Context context, WindowManagerService windowManager) { Intent intent = new Intent(); intent.setComponent(new ComponentName("com.android.systemui", diff --git a/services/net/Android.bp b/services/net/Android.bp index 8ad4d7679107..486d15d918bf 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -7,6 +7,19 @@ java_library_static { ] } +java_library_static { + name: "ipmemorystore-client", + sdk_version: "system_current", + srcs: [ + ":framework-annotations", + "java/android/net/IpMemoryStoreClient.java", + "java/android/net/ipmemorystore/**.java", + ], + static_libs: [ + "ipmemorystore-aidl-interfaces-java", + ] +} + filegroup { name: "services-networkstack-shared-srcs", srcs: [ diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java new file mode 100644 index 000000000000..9248299e178d --- /dev/null +++ b/services/net/java/android/net/IpMemoryStore.java @@ -0,0 +1,62 @@ +/* + * 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 android.net; + +import android.annotation.NonNull; +import android.content.Context; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * Manager class used to communicate with the ip memory store service in the network stack, + * which is running in a separate module. + * @hide +*/ +public class IpMemoryStore extends IpMemoryStoreClient { + private final CompletableFuture<IIpMemoryStore> mService; + + public IpMemoryStore(@NonNull final Context context) { + super(context); + mService = new CompletableFuture<>(); + getNetworkStackClient().fetchIpMemoryStore( + new IIpMemoryStoreCallbacks.Stub() { + @Override + public void onIpMemoryStoreFetched(final IIpMemoryStore memoryStore) { + mService.complete(memoryStore); + } + }); + } + + @Override + protected IIpMemoryStore getService() throws InterruptedException, ExecutionException { + return mService.get(); + } + + @VisibleForTesting + protected NetworkStackClient getNetworkStackClient() { + return NetworkStackClient.getInstance(); + } + + /** Gets an instance of the memory store */ + @NonNull + public static IpMemoryStore getMemoryStore(final Context context) { + return new IpMemoryStore(context); + } +} diff --git a/core/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStoreClient.java index 2f4d9bc6a89a..2f4fdbd8a4a7 100644 --- a/core/java/android/net/IpMemoryStore.java +++ b/services/net/java/android/net/IpMemoryStoreClient.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * 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. @@ -18,7 +18,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemService; import android.content.Context; import android.net.ipmemorystore.Blob; import android.net.ipmemorystore.IOnBlobRetrievedListener; @@ -27,23 +26,34 @@ import android.net.ipmemorystore.IOnNetworkAttributesRetrieved; import android.net.ipmemorystore.IOnSameNetworkResponseListener; import android.net.ipmemorystore.IOnStatusListener; import android.net.ipmemorystore.NetworkAttributes; +import android.net.ipmemorystore.Status; +import android.net.ipmemorystore.StatusParcelable; import android.os.RemoteException; +import android.util.Log; -import com.android.internal.util.Preconditions; +import java.util.concurrent.ExecutionException; /** - * The interface for system components to access the IP memory store. - * @see com.android.server.net.ipmemorystore.IpMemoryStoreService + * service used to communicate with the ip memory store service in network stack, + * which is running in a separate module. * @hide */ -@SystemService(Context.IP_MEMORY_STORE_SERVICE) -public class IpMemoryStore { - @NonNull final Context mContext; - @NonNull final IIpMemoryStore mService; +public abstract class IpMemoryStoreClient { + private static final String TAG = IpMemoryStoreClient.class.getSimpleName(); + private final Context mContext; - public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) { - mContext = Preconditions.checkNotNull(context, "missing context"); - mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore"); + public IpMemoryStoreClient(@NonNull final Context context) { + if (context == null) throw new IllegalArgumentException("missing context"); + mContext = context; + } + + @NonNull + protected abstract IIpMemoryStore getService() throws InterruptedException, ExecutionException; + + protected StatusParcelable internalErrorStatus() { + final StatusParcelable error = new StatusParcelable(); + error.resultCode = Status.ERROR_UNKNOWN; + return error; } /** @@ -66,9 +76,13 @@ public class IpMemoryStore { @NonNull final NetworkAttributes attributes, @Nullable final IOnStatusListener listener) { try { - mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener); + try { + getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), listener); + } catch (InterruptedException | ExecutionException m) { + listener.onComplete(internalErrorStatus()); + } } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "Error storing network attributes", e); } } @@ -87,9 +101,13 @@ public class IpMemoryStore { @NonNull final String name, @NonNull final Blob data, @Nullable final IOnStatusListener listener) { try { - mService.storeBlob(l2Key, clientId, name, data, listener); + try { + getService().storeBlob(l2Key, clientId, name, data, listener); + } catch (InterruptedException | ExecutionException m) { + listener.onComplete(internalErrorStatus()); + } } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "Error storing blob", e); } } @@ -110,9 +128,13 @@ public class IpMemoryStore { public void findL2Key(@NonNull final NetworkAttributes attributes, @NonNull final IOnL2KeyResponseListener listener) { try { - mService.findL2Key(attributes.toParcelable(), listener); + try { + getService().findL2Key(attributes.toParcelable(), listener); + } catch (InterruptedException | ExecutionException m) { + listener.onL2KeyResponse(internalErrorStatus(), null); + } } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "Error finding L2 Key", e); } } @@ -128,9 +150,13 @@ public class IpMemoryStore { public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2, @NonNull final IOnSameNetworkResponseListener listener) { try { - mService.isSameNetwork(l2Key1, l2Key2, listener); + try { + getService().isSameNetwork(l2Key1, l2Key2, listener); + } catch (InterruptedException | ExecutionException m) { + listener.onSameNetworkResponse(internalErrorStatus(), null); + } } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "Error checking for network sameness", e); } } @@ -146,9 +172,13 @@ public class IpMemoryStore { public void retrieveNetworkAttributes(@NonNull final String l2Key, @NonNull final IOnNetworkAttributesRetrieved listener) { try { - mService.retrieveNetworkAttributes(l2Key, listener); + try { + getService().retrieveNetworkAttributes(l2Key, listener); + } catch (InterruptedException | ExecutionException m) { + listener.onNetworkAttributesRetrieved(internalErrorStatus(), null, null); + } } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "Error retrieving network attributes", e); } } @@ -166,14 +196,13 @@ public class IpMemoryStore { public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId, @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) { try { - mService.retrieveBlob(l2Key, clientId, name, listener); + try { + getService().retrieveBlob(l2Key, clientId, name, listener); + } catch (InterruptedException | ExecutionException m) { + listener.onBlobRetrieved(internalErrorStatus(), null, null, null); + } } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "Error retrieving blob", e); } } - - /** Gets an instance of the memory store */ - public static IpMemoryStore getMemoryStore(final Context context) { - return (IpMemoryStore) context.getSystemService(Context.IP_MEMORY_STORE_SERVICE); - } } diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java index cc09fe305070..7befd0870c00 100644 --- a/services/net/java/android/net/NetworkStackClient.java +++ b/services/net/java/android/net/NetworkStackClient.java @@ -130,6 +130,21 @@ public class NetworkStackClient { }); } + /** + * Get an instance of the IpMemoryStore. + * + * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks. + */ + public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) { + requestConnector(connector -> { + try { + connector.fetchIpMemoryStore(cb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + }); + } + private class NetworkStackConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java index 99d36c504e5c..398a6b31cbce 100644 --- a/core/java/android/net/TcpKeepalivePacketData.java +++ b/services/net/java/android/net/TcpKeepalivePacketData.java @@ -167,8 +167,9 @@ public class TcpKeepalivePacketData extends KeepalivePacketData implements Parce tcpWndScale); } - /* Parcelable Implementation. */ - /* Note that this object implements parcelable (and needs to keep doing this as it inherits + /** + * Parcelable Implementation. + * Note that this object implements parcelable (and needs to keep doing this as it inherits * from a class that does), but should usually be parceled as a stable parcelable using * the toStableParcelable() and fromStableParcelable() methods. */ @@ -194,7 +195,7 @@ public class TcpKeepalivePacketData extends KeepalivePacketData implements Parce } /** Parcelable Creator. */ - public static final @android.annotation.NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR = + public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR = new Parcelable.Creator<TcpKeepalivePacketData>() { public TcpKeepalivePacketData createFromParcel(Parcel in) { return new TcpKeepalivePacketData(in); diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java index 6a9eae00e3ff..6a9eae00e3ff 100644 --- a/core/java/android/net/ipmemorystore/NetworkAttributes.java +++ b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java index 291aca8fc611..291aca8fc611 100644 --- a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java +++ b/services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java diff --git a/core/java/android/net/ipmemorystore/Status.java b/services/net/java/android/net/ipmemorystore/Status.java index cacd42d713c2..13242c03ce01 100644 --- a/core/java/android/net/ipmemorystore/Status.java +++ b/services/net/java/android/net/ipmemorystore/Status.java @@ -32,6 +32,7 @@ public class Status { public static final int ERROR_ILLEGAL_ARGUMENT = -2; public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -3; public static final int ERROR_STORAGE = -4; + public static final int ERROR_UNKNOWN = -5; public final int resultCode; diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java index 6386b3b396ae..7c91b6459fc8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java @@ -15,7 +15,10 @@ */ package com.android.server; +import static android.app.AlarmManager.ELAPSED_REALTIME; import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; +import static android.app.AlarmManager.RTC; +import static android.app.AlarmManager.RTC_WAKEUP; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; @@ -254,14 +257,22 @@ public class AlarmManagerServiceTest { } private void setTestAlarm(int type, long triggerTime, PendingIntent operation) { + setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID); + } + + private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) { mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0, operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null, - TEST_CALLING_UID, TEST_CALLING_PACKAGE); + callingUid, TEST_CALLING_PACKAGE); } private PendingIntent getNewMockPendingIntent() { + return getNewMockPendingIntent(TEST_CALLING_UID); + } + + private PendingIntent getNewMockPendingIntent(int mockUid) { final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS); - when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID); + when(mockPi.getCreatorUid()).thenReturn(mockUid); when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE); return mockPi; } @@ -724,6 +735,91 @@ public class AlarmManagerServiceTest { verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL); } + @Test + public void alarmCountKeyedOnCallingUid() { + final int mockCreatorUid = 431412; + final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi); + assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); + assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1)); + } + + @Test + public void alarmCountOnSet() { + final int numAlarms = 103; + final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME}; + for (int i = 1; i <= numAlarms; i++) { + setTestAlarm(types[i % 4], mNowElapsedTest + i, getNewMockPendingIntent()); + assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); + } + } + + @Test + public void alarmCountOnExpiration() throws InterruptedException { + final int numAlarms = 8; // This test is slow + for (int i = 0; i < numAlarms; i++) { + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); + } + int expired = 0; + while (expired < numAlarms) { + mNowElapsedTest = mTestTimer.getElapsed(); + mTestTimer.expire(); + expired++; + assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); + } + } + + @Test + public void alarmCountOnUidRemoved() { + final int numAlarms = 10; + for (int i = 0; i < numAlarms; i++) { + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); + } + assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); + mService.removeLocked(TEST_CALLING_UID); + assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); + } + + @Test + public void alarmCountOnPackageRemoved() { + final int numAlarms = 10; + for (int i = 0; i < numAlarms; i++) { + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); + } + assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); + mService.removeLocked(TEST_CALLING_PACKAGE); + assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); + } + + @Test + public void alarmCountOnUserRemoved() { + final int mockUserId = 15; + final int numAlarms = 10; + for (int i = 0; i < numAlarms; i++) { + int mockUid = UserHandle.getUid(mockUserId, 1234 + i); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, + getNewMockPendingIntent(mockUid), mockUid); + } + assertEquals(numAlarms, mService.mAlarmsPerUid.size()); + mService.removeUserLocked(mockUserId); + assertEquals(0, mService.mAlarmsPerUid.size()); + } + + @Test + public void alarmCountOnAlarmRemoved() { + final int numAlarms = 10; + final PendingIntent[] pis = new PendingIntent[numAlarms]; + for (int i = 0; i < numAlarms; i++) { + pis[i] = getNewMockPendingIntent(); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]); + } + assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); + for (int i = 0; i < numAlarms; i++) { + mService.removeLocked(pis[i], null); + assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); + } + } + @After public void tearDown() { if (mMockingSession != null) { diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 8e78a5686b85..c45122ec861d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -52,6 +52,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkPolicyManager; import android.os.Build; +import android.os.Looper; import android.os.SystemClock; import android.util.DataUnit; @@ -102,6 +103,8 @@ public class ConnectivityControllerTest { LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal); + when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); + // Freeze the clocks at this moment in time JobSchedulerService.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC); diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java index 86e859809ffd..2e5efbd1deef 100644 --- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java @@ -28,6 +28,7 @@ import android.app.NotificationManager; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; +import android.os.PowerManager; import android.provider.Settings.Global; import androidx.test.filters.SmallTest; @@ -452,6 +453,21 @@ public class BatterySaverStateMachineTest { assertEquals(true, mDevice.batterySaverEnabled); assertEquals(30, mPersistedState.batteryLevel); assertEquals(true, mPersistedState.batteryLow); + + // Disable auto battery saver. + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); + mDevice.setBatteryLevel(25); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(25, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + // PowerManager sets batteryLow to true at 15% if battery saver trigger level is lower. + mDevice.setBatteryLevel(15); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(15, mPersistedState.batteryLevel); + assertEquals(true, mPersistedState.batteryLow); } @Test @@ -542,6 +558,12 @@ public class BatterySaverStateMachineTest { assertEquals(100, mPersistedState.batteryLevel); assertEquals(false, mPersistedState.batteryLow); + mDevice.setBatteryLevel(97); + + assertEquals(true, mDevice.batterySaverEnabled); // Stays on. + assertEquals(97, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + mDevice.setBatteryLevel(95); assertEquals(true, mDevice.batterySaverEnabled); // Stays on. @@ -719,6 +741,48 @@ public class BatterySaverStateMachineTest { } @Test + public void testAutoBatterySaver_withSticky_withAutoOffToggled() { + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50); + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1); + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90); + + // Scenario 1: User turns BS on manually above the threshold, it shouldn't turn off even + // with battery level change above threshold. + mDevice.setBatteryLevel(100); + mTarget.setBatterySaverEnabledManually(true); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(100, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + mDevice.setBatteryLevel(95); + + assertEquals(true, mDevice.batterySaverEnabled); // Stays on. + assertEquals(95, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + // Disable auto disable while in the pending sticky state. BS should reactivate after + // unplug. + mDevice.setPowered(true); + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0); + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS should activate. + assertEquals(95, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + // Enable auto disable while in the pending sticky state. Sticky should turn off after + // unplug. + mDevice.setPowered(true); + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1); + mDevice.setPowered(false); + + assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled. + assertEquals(95, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + } + + @Test public void testAutoBatterySaver_withStickyDisabled() { when(mMockResources.getBoolean( com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled)) @@ -739,7 +803,9 @@ public class BatterySaverStateMachineTest { assertEquals(30, mPersistedState.batteryLevel); assertEquals(true, mPersistedState.batteryLow); + mDevice.setPowered(true); mDevice.setBatteryLevel(80); + mDevice.setPowered(false); assertEquals(false, mDevice.batterySaverEnabled); // Not sticky. assertEquals(80, mPersistedState.batteryLevel); @@ -830,10 +896,9 @@ public class BatterySaverStateMachineTest { assertEquals(90, mPersistedState.batteryLevel); assertEquals(false, mPersistedState.batteryLow); - // Reboot -- setting BS from adb is also sticky. + // Reboot -- LOW_POWER_MODE shouldn't be persisted. initDevice(); - - assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(false, mDevice.batterySaverEnabled); assertEquals(90, mPersistedState.batteryLevel); assertEquals(false, mPersistedState.batteryLow); } @@ -841,7 +906,8 @@ public class BatterySaverStateMachineTest { @Test public void testAutoBatterySaver_smartBatterySaverEnabled() { mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50); - mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1); + mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, + PowerManager.POWER_SAVER_MODE_DYNAMIC); mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0); assertEquals(false, mDevice.batterySaverEnabled); @@ -922,8 +988,8 @@ public class BatterySaverStateMachineTest { mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71); mDevice.setBatteryLevel(mPersistedState.batteryLevel); - // changes are only registered if some battery level changed - assertEquals(false, mDevice.batterySaverEnabled); + // Changes should register immediately. + assertEquals(true, mDevice.batterySaverEnabled); assertEquals(70, mPersistedState.batteryLevel); mDevice.setBatteryLevel(69); @@ -935,8 +1001,8 @@ public class BatterySaverStateMachineTest { mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60); mDevice.setBatteryLevel(mPersistedState.batteryLevel); - // changes are only registered if battery level changed - assertEquals(true, mDevice.batterySaverEnabled); + // Changes should register immediately. + assertEquals(false, mDevice.batterySaverEnabled); assertEquals(69, mPersistedState.batteryLevel); mDevice.setBatteryLevel(68); @@ -956,4 +1022,220 @@ public class BatterySaverStateMachineTest { assertEquals(true, mDevice.batterySaverEnabled); assertEquals(30, mPersistedState.batteryLevel); } + + @Test + public void testAutoBatterySaver_snoozed_autoEnabled() { + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 30); + // Test dynamic threshold higher than automatic to make sure it doesn't interfere when it's + // not enabled. + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50); + mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, + PowerManager.POWER_SAVER_MODE_PERCENTAGE); + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(100, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(90); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(51); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(51, mPersistedState.batteryLevel); + + // Hit dynamic threshold. BS should be disabled since dynamic is off + mDevice.setBatteryLevel(50); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(50, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(30); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mDevice.setPowered(true); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze. + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(20); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(20, mPersistedState.batteryLevel); + + // Lower threshold. Level is still below, so should still be snoozed. + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 25); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(20, mPersistedState.batteryLevel); + + // Lower threshold even more. Battery no longer considered "low" so snoozing should be + // disabled. + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 10); + // "batteryLow" is set in setBatteryLevel. + mDevice.setBatteryLevel(19); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(19, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(10); + + assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing. + assertEquals(10, mPersistedState.batteryLevel); + + mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze. + + // Plug in and out, snooze will reset. + mDevice.setPowered(true); + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(10, mPersistedState.batteryLevel); + + mDevice.setPowered(true); + mDevice.setBatteryLevel(60); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(60, mPersistedState.batteryLevel); + + // Test toggling resets snooze. + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50); + mDevice.setPowered(false); + mDevice.setBatteryLevel(45); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(45, mPersistedState.batteryLevel); + + mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze. + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(45, mPersistedState.batteryLevel); + + // Disable and re-enable. + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50); + + assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset + assertEquals(45, mPersistedState.batteryLevel); + } + + @Test + public void testAutoBatterySaver_snoozed_dynamicEnabled() { + // Test auto threshold higher than dynamic to make sure it doesn't interfere when it's + // not enabled. + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50); + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 30); + mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, + PowerManager.POWER_SAVER_MODE_DYNAMIC); + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(100, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(90); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(51); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(51, mPersistedState.batteryLevel); + + // Hit automatic threshold. BS should be disabled since automatic is off + mDevice.setBatteryLevel(50); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(50, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(30); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mDevice.setPowered(true); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze. + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(20); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(20, mPersistedState.batteryLevel); + + // Lower threshold. Level is still below, so should still be snoozed. + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 25); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(20, mPersistedState.batteryLevel); + + // Lower threshold even more. Battery no longer considered "low" so snoozing should be + // disabled. + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 10); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(20, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(10); + + assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing. + assertEquals(10, mPersistedState.batteryLevel); + + mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze. + + // Plug in and out, snooze will reset. + mDevice.setPowered(true); + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(10, mPersistedState.batteryLevel); + + mDevice.setPowered(true); + mDevice.setBatteryLevel(60); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(60, mPersistedState.batteryLevel); + + // Test toggling resets snooze. + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50); + mDevice.setPowered(false); + mDevice.setBatteryLevel(45); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(45, mPersistedState.batteryLevel); + + mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze. + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(45, mPersistedState.batteryLevel); + + // Disable and re-enable. + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0); + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1); + + assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset + assertEquals(45, mPersistedState.batteryLevel); + } } diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java index 26b122411c6b..caf6c9cac509 100644 --- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java +++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java @@ -1138,7 +1138,7 @@ public class IPackageManagerStub implements IPackageManager { } @Override - public String getContentCaptureServicePackageName() throws RemoteException { + public String getSystemCaptionsServicePackageName() throws RemoteException { return null; } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 95043810128a..cd095a5fa6ff 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -250,7 +250,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setRank(123) .setPerson(makePerson("person", "personKey", "personUri")) - .setLongLived() + .setLongLived(true) .setExtras(pb) .build(); si.addFlags(ShortcutInfo.FLAG_PINNED); @@ -352,7 +352,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setRank(123) .setPerson(makePerson("person", "personKey", "personUri")) - .setLongLived() + .setLongLived(true) .setExtras(pb) .build(); sorig.addFlags(ShortcutInfo.FLAG_PINNED); diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java index a2f1f01b689f..a1a58b49329f 100644 --- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java +++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java @@ -105,6 +105,13 @@ public class AttentionDetectorTest extends AndroidTestCase { } @Test + public void testOnUserActivity_doesntCrashIfNoAttentionService() { + mAttentionManagerInternal = null; + registerAttention(); + // Does not crash. + } + + @Test public void onUserActivity_ignoresWhiteListedActivityTypes() { for (int i = 0; i < NUM_USER_ACTIVITY_TYPES; i++) { int result = mAttentionDetector.onUserActivity(SystemClock.uptimeMillis(), i); diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java index 5556a150cf3a..febb79540fea 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java @@ -43,7 +43,6 @@ import org.mockito.MockitoAnnotations; */ @SmallTest @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { @Mock diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 1e02a12e83db..329af952c07a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -38,9 +38,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import android.app.AppOpsManager; -import android.app.IActivityManager; import android.app.IActivityTaskManager; -import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; @@ -50,7 +48,6 @@ import android.platform.test.annotations.Presubmit; import android.util.Log; import android.view.IWindowManager; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.server.am.AssistDataRequester; @@ -88,12 +85,10 @@ public class AssistDataRequesterTest extends ActivityTestsBase { private static final int TEST_UID = 0; private static final String TEST_PACKAGE = ""; - private Context mContext; private AssistDataRequester mDataRequester; private Callbacks mCallbacks; private Object mCallbacksLock; private Handler mHandler; - private IActivityManager mAm; private IActivityTaskManager mAtm; private IWindowManager mWm; private AppOpsManager mAppOpsManager; @@ -109,7 +104,6 @@ public class AssistDataRequesterTest extends ActivityTestsBase { @Before public void setUp() throws Exception { - mAm = mock(IActivityManager.class); mAtm = mock(IActivityTaskManager.class); mWm = mock(IWindowManager.class); mAppOpsManager = mock(AppOpsManager.class); @@ -118,7 +112,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { mCallbacks = new Callbacks(); mDataRequester = new AssistDataRequester(mContext, mWm, mAppOpsManager, mCallbacks, mCallbacksLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT); - + mDataRequester.mActivityTaskManager = mAtm; // Gate the continuation of the assist data callbacks until we are ready within the tests mGate = new CountDownLatch(1); doAnswer(invocation -> { @@ -155,7 +149,6 @@ public class AssistDataRequesterTest extends ActivityTestsBase { .checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString()); } - @FlakyTest(bugId = 124088319) @Test public void testRequestData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -176,7 +169,6 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 0, 0, 0); } - @FlakyTest(bugId = 124088319) @Test public void testCurrentAppDisallow_expectNullCallbacks() throws Exception { setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -187,7 +179,6 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } - @FlakyTest(bugId = 124088319) @Test public void testProcessPendingData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -245,7 +236,6 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } - @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -259,7 +249,6 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(0, 1, 0, 1); } - @FlakyTest(bugId = 124088319) @Test public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, @@ -270,7 +259,6 @@ public class AssistDataRequesterTest extends ActivityTestsBase { assertReceivedDataCount(5, 5, 0, 0); } - @FlakyTest(bugId = 124088319) @Test public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 98333b244e3b..e60e54c9e44f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -25,6 +25,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; @@ -58,12 +60,15 @@ import android.annotation.SuppressLint; import android.app.WindowConfiguration; import android.content.res.Configuration; import android.graphics.Rect; +import android.graphics.Region; import android.metrics.LogMaker; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; +import android.util.MutableBoolean; import android.view.DisplayCutout; import android.view.Gravity; +import android.view.ISystemGestureExclusionListener; import android.view.MotionEvent; import android.view.Surface; import android.view.ViewRootImpl; @@ -683,6 +688,60 @@ public class DisplayContentTests extends WindowTestsBase { } @Test + public void testUpdateSystemGestureExclusion() throws Exception { + final DisplayContent dc = createNewDisplay(); + final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; + win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40))); + + dc.setLayoutNeeded(); + dc.performLayout(true /* initial */, false /* updateImeWindows */); + + win.setHasSurface(true); + dc.updateSystemGestureExclusion(); + + final MutableBoolean invoked = new MutableBoolean(false); + final ISystemGestureExclusionListener.Stub verifier = + new ISystemGestureExclusionListener.Stub() { + @Override + public void onSystemGestureExclusionChanged(int displayId, Region actual) { + Region expected = Region.obtain(); + expected.set(10, 20, 30, 40); + assertEquals(expected, actual); + invoked.value = true; + } + }; + try { + dc.registerSystemGestureExclusionListener(verifier); + } finally { + dc.unregisterSystemGestureExclusionListener(verifier); + } + assertTrue("SystemGestureExclusionListener was not invoked", invoked.value); + } + + @Test + public void testCalculateSystemGestureExclusion() throws Exception { + final DisplayContent dc = createNewDisplay(); + final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; + win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40))); + + final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "win2"); + win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; + win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50))); + + dc.setLayoutNeeded(); + dc.performLayout(true /* initial */, false /* updateImeWindows */); + + win.setHasSurface(true); + win2.setHasSurface(true); + + final Region expected = Region.obtain(); + expected.set(20, 30, 40, 50); + assertEquals(expected, dc.calculateSystemGestureExclusion()); + } + + @Test public void testOrientationChangeLogging() { MetricsLogger mockLogger = mock(MetricsLogger.class); Configuration oldConfig = new Configuration(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index b9e9909c2dc9..d8a01b9eb9b4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -159,7 +159,6 @@ public class TaskStackChangedListenerTest { * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted. */ @Test - @FlakyTest(detail = "Promote to presubmit when shown to be stable.") public void testTaskChangeCallBacks() throws Exception { final Object[] params = new Object[2]; final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index b03f63b9159f..4f8fe5b10f19 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -87,7 +87,6 @@ import java.util.LinkedList; */ @SmallTest @Presubmit -@FlakyTest(bugId = 124127512) public class WindowStateTests extends WindowTestsBase { private static int sPreviousNewInsetsMode; @@ -363,7 +362,6 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(app.canAffectSystemUiFlags()); } - @FlakyTest(detail = "Promote to presubmit when shown to be stable.") @Test public void testVisibleWithInsetsProvider() throws Exception { final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar"); diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index f0a26f50a0b8..ca264f738e1d 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -318,8 +318,8 @@ public final class DataFailCause { public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC; /** APN has been disabled. */ public static final int APN_DISABLED = 0x7FD; - /** PPP inactivity timer expired. */ - public static final int PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE; + /** Maximum PPP inactivity timer expired. */ + public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE; /** IPv6 address transfer failed. */ public static final int IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF; /** Target RAT swap failed. */ @@ -339,12 +339,12 @@ public final class DataFailCause { * IPv4 data call bring up is rejected because the UE already maintains the allotted maximum * number of IPv4 data connections. */ - public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 0x804; + public static final int MAX_IPV4_CONNECTIONS = 0x804; /** * IPv6 data call bring up is rejected because the UE already maintains the allotted maximum * number of IPv6 data connections. */ - public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 0x805; + public static final int MAX_IPV6_CONNECTIONS = 0x805; /** * New PDN bring up is rejected during interface selection because the UE has already allotted * the available interfaces for other PDNs. @@ -416,7 +416,7 @@ public final class DataFailCause { */ public static final int CHANNEL_ACQUISITION_FAILURE = 0x81E; /** Maximum access probes transmitted. */ - public static final int ACCESS_PROBE_LIMIT_REACHED = 0x81F; + public static final int MAX_ACCESS_PROBE = 0x81F; /** Concurrent service is not supported by base station. */ public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820; /** There was no response received from the base station. */ @@ -1079,14 +1079,14 @@ public final class DataFailCause { SIM_CARD_CHANGED, LOW_POWER_MODE_OR_POWERING_DOWN, APN_DISABLED, - PPP_INACTIVITY_TIMER_EXPIRED, + MAX_PPP_INACTIVITY_TIMER_EXPIRED, IPV6_ADDRESS_TRANSFER_FAILED, TRAT_SWAP_FAILED, EHRPD_TO_HRPD_FALLBACK, MIP_CONFIG_FAILURE, PDN_INACTIVITY_TIMER_EXPIRED, - IPV4_CONNECTIONS_LIMIT_REACHED, - IPV6_CONNECTIONS_LIMIT_REACHED, + MAX_IPV4_CONNECTIONS, + MAX_IPV6_CONNECTIONS, APN_MISMATCH, IP_VERSION_MISMATCH, DUN_CALL_DISALLOWED, @@ -1112,7 +1112,7 @@ public final class DataFailCause { CDMA_INCOMING_CALL, CDMA_ALERT_STOP, CHANNEL_ACQUISITION_FAILURE, - ACCESS_PROBE_LIMIT_REACHED, + MAX_ACCESS_PROBE, CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION, NO_RESPONSE_FROM_BASE_STATION, REJECTED_BY_BASE_STATION, @@ -1447,14 +1447,14 @@ public final class DataFailCause { sFailCauseMap.put(SIM_CARD_CHANGED, "SIM_CARD_CHANGED"); sFailCauseMap.put(LOW_POWER_MODE_OR_POWERING_DOWN, "LOW_POWER_MODE_OR_POWERING_DOWN"); sFailCauseMap.put(APN_DISABLED, "APN_DISABLED"); - sFailCauseMap.put(PPP_INACTIVITY_TIMER_EXPIRED, "PPP_INACTIVITY_TIMER_EXPIRED"); + sFailCauseMap.put(MAX_PPP_INACTIVITY_TIMER_EXPIRED, "MAX_PPP_INACTIVITY_TIMER_EXPIRED"); sFailCauseMap.put(IPV6_ADDRESS_TRANSFER_FAILED, "IPV6_ADDRESS_TRANSFER_FAILED"); sFailCauseMap.put(TRAT_SWAP_FAILED, "TRAT_SWAP_FAILED"); sFailCauseMap.put(EHRPD_TO_HRPD_FALLBACK, "EHRPD_TO_HRPD_FALLBACK"); sFailCauseMap.put(MIP_CONFIG_FAILURE, "MIP_CONFIG_FAILURE"); sFailCauseMap.put(PDN_INACTIVITY_TIMER_EXPIRED, "PDN_INACTIVITY_TIMER_EXPIRED"); - sFailCauseMap.put(IPV4_CONNECTIONS_LIMIT_REACHED, "IPV4_CONNECTIONS_LIMIT_REACHED"); - sFailCauseMap.put(IPV6_CONNECTIONS_LIMIT_REACHED, "IPV6_CONNECTIONS_LIMIT_REACHED"); + sFailCauseMap.put(MAX_IPV4_CONNECTIONS, "MAX_IPV4_CONNECTIONS"); + sFailCauseMap.put(MAX_IPV6_CONNECTIONS, "MAX_IPV6_CONNECTIONS"); sFailCauseMap.put(APN_MISMATCH, "APN_MISMATCH"); sFailCauseMap.put(IP_VERSION_MISMATCH, "IP_VERSION_MISMATCH"); sFailCauseMap.put(DUN_CALL_DISALLOWED, "DUN_CALL_DISALLOWED"); @@ -1480,7 +1480,7 @@ public final class DataFailCause { sFailCauseMap.put(CDMA_INCOMING_CALL, "CDMA_INCOMING_CALL"); sFailCauseMap.put(CDMA_ALERT_STOP, "CDMA_ALERT_STOP"); sFailCauseMap.put(CHANNEL_ACQUISITION_FAILURE, "CHANNEL_ACQUISITION_FAILURE"); - sFailCauseMap.put(ACCESS_PROBE_LIMIT_REACHED, "ACCESS_PROBE_LIMIT_REACHED"); + sFailCauseMap.put(MAX_ACCESS_PROBE, "MAX_ACCESS_PROBE"); sFailCauseMap.put(CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION, "CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION"); sFailCauseMap.put(NO_RESPONSE_FROM_BASE_STATION, "NO_RESPONSE_FROM_BASE_STATION"); diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index c31a14edff10..9145b2532817 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -27,7 +27,9 @@ import android.telephony.TelephonyManager.NetworkType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -36,7 +38,7 @@ import java.util.stream.Collectors; * @hide */ @SystemApi -public class NetworkRegistrationInfo implements Parcelable { +public final class NetworkRegistrationInfo implements Parcelable { /** * Network domain * @hide @@ -51,41 +53,42 @@ public class NetworkRegistrationInfo implements Parcelable { public static final int DOMAIN_PS = 2; /** - * Registration state + * Network registration state * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "REG_STATE_", - value = {REG_STATE_NOT_REG_NOT_SEARCHING, REG_STATE_HOME, REG_STATE_NOT_REG_SEARCHING, - REG_STATE_DENIED, REG_STATE_UNKNOWN, REG_STATE_ROAMING}) - public @interface RegState {} - - /** Not registered. The device is not currently searching a new operator to register */ - public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0; - /** Registered on home network */ - public static final int REG_STATE_HOME = 1; - /** Not registered. The device is currently searching a new operator to register */ - public static final int REG_STATE_NOT_REG_SEARCHING = 2; - /** Registration denied */ - public static final int REG_STATE_DENIED = 3; - /** Registration state is unknown */ - public static final int REG_STATE_UNKNOWN = 4; - /** Registered on roaming network */ - public static final int REG_STATE_ROAMING = 5; + @IntDef(prefix = "REGISTRATION_STATE_", + value = {REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, REGISTRATION_STATE_HOME, + REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, REGISTRATION_STATE_DENIED, + REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING}) + public @interface RegistrationState {} + + /** Not registered. The device is not currently searching a new operator to register. */ + public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; + /** Registered on home network. */ + public static final int REGISTRATION_STATE_HOME = 1; + /** Not registered. The device is currently searching a new operator to register. */ + public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; + /** Registration denied. */ + public static final int REGISTRATION_STATE_DENIED = 3; + /** Registration state is unknown. */ + public static final int REGISTRATION_STATE_UNKNOWN = 4; + /** Registered on roaming network. */ + public static final int REGISTRATION_STATE_ROAMING = 5; /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "NR_STATUS_", - value = {NR_STATUS_NONE, NR_STATUS_RESTRICTED, NR_STATUS_NOT_RESTRICTED, - NR_STATUS_CONNECTED}) - public @interface NRStatus {} + @IntDef(prefix = "NR_STATE_", + value = {NR_STATE_NONE, NR_STATE_RESTRICTED, NR_STATE_NOT_RESTRICTED, + NR_STATE_CONNECTED}) + public @interface NRState {} /** * The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR * Dual Connectivity(EN-DC). * @hide */ - public static final int NR_STATUS_NONE = -1; + public static final int NR_STATE_NONE = -1; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but @@ -93,7 +96,7 @@ public class NetworkRegistrationInfo implements Parcelable { * the selected PLMN. * @hide */ - public static final int NR_STATUS_RESTRICTED = 1; + public static final int NR_STATE_RESTRICTED = 1; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both @@ -101,14 +104,14 @@ public class NetworkRegistrationInfo implements Parcelable { * selected PLMN. * @hide */ - public static final int NR_STATUS_NOT_RESTRICTED = 2; + public static final int NR_STATE_NOT_RESTRICTED = 2; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and * also connected to at least one 5G cell as a secondary serving cell. * @hide */ - public static final int NR_STATUS_CONNECTED = 3; + public static final int NR_STATE_CONNECTED = 3; /** * Supported service type @@ -116,23 +119,36 @@ public class NetworkRegistrationInfo implements Parcelable { */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "SERVICE_TYPE_", - value = {SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS, SERVICE_TYPE_VIDEO, - SERVICE_TYPE_EMERGENCY}) + value = {SERVICE_TYPE_UNKNOWN, SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS, + SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY}) public @interface ServiceType {} + /** Unkown service */ + public static final int SERVICE_TYPE_UNKNOWN = 0; + + /** Voice service */ public static final int SERVICE_TYPE_VOICE = 1; + + /** Data service */ public static final int SERVICE_TYPE_DATA = 2; + + /** SMS service */ public static final int SERVICE_TYPE_SMS = 3; + + /** Video service */ public static final int SERVICE_TYPE_VIDEO = 4; + + /** Emergency service */ public static final int SERVICE_TYPE_EMERGENCY = 5; @Domain private final int mDomain; + @TransportType private final int mTransportType; - @RegState - private final int mRegState; + @RegistrationState + private final int mRegistrationState; /** * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type @@ -144,15 +160,15 @@ public class NetworkRegistrationInfo implements Parcelable { @NetworkType private int mAccessNetworkTechnology; - @NRStatus - private int mNrStatus; + @NRState + private int mNrState; private final int mRejectCause; private final boolean mEmergencyOnly; @ServiceType - private final int[] mAvailableServices; + private final ArrayList<Integer> mAvailableServices; @Nullable private CellIdentity mCellIdentity; @@ -167,54 +183,56 @@ public class NetworkRegistrationInfo implements Parcelable { * @param domain Network domain. Must be a {@link Domain}. For transport type * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}. * @param transportType Transport type. - * @param regState Network registration state. Must be one of the {@link RegState}. For - * transport type {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only - * {@link #REG_STATE_HOME} and {@link #REG_STATE_NOT_REG_NOT_SEARCHING} are valid states. + * @param registrationState Network registration state. For transport type + * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only + * {@link #REGISTRATION_STATE_HOME} and {@link #REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING} + * are valid states. * @param accessNetworkTechnology Access network technology.For transport type * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, set to * {@link TelephonyManager#NETWORK_TYPE_IWLAN}. - * @param rejectCause Reason for denial if the registration state is {@link #REG_STATE_DENIED}. - * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008 - * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA. If - * the reject cause is not supported or unknown, set it to 0. + * @param rejectCause Reason for denial if the registration state is + * {@link #REGISTRATION_STATE_DENIED}. Depending on {@code accessNetworkTechnology}, the values + * are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 + * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0. * // TODO: Add IWLAN reject cause reference * @param emergencyOnly True if this registration is for emergency only. - * @param availableServices The list of the supported services. Each element must be one of - * the {@link ServiceType}. + * @param availableServices The list of the supported services. * @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the * information is not available. */ - public NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType, - @RegState int regState, + private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType, + @RegistrationState int registrationState, @NetworkType int accessNetworkTechnology, int rejectCause, boolean emergencyOnly, - @NonNull @ServiceType int[] availableServices, + @Nullable @ServiceType List<Integer> availableServices, @Nullable CellIdentity cellIdentity) { mDomain = domain; mTransportType = transportType; - mRegState = regState; - mRoamingType = (regState == REG_STATE_ROAMING) + mRegistrationState = registrationState; + mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING) ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING; mAccessNetworkTechnology = accessNetworkTechnology; mRejectCause = rejectCause; - mAvailableServices = availableServices; + mAvailableServices = (availableServices != null) + ? new ArrayList<>(availableServices) : new ArrayList<>(); mCellIdentity = cellIdentity; mEmergencyOnly = emergencyOnly; - mNrStatus = NR_STATUS_NONE; + mNrState = NR_STATE_NONE; } /** * Constructor for voice network registration info. * @hide */ - public NetworkRegistrationInfo(int domain, @TransportType int transportType, int regState, - int accessNetworkTechnology, int rejectCause, - boolean emergencyOnly, int[] availableServices, + public NetworkRegistrationInfo(int domain, @TransportType int transportType, + int registrationState, int accessNetworkTechnology, + int rejectCause, boolean emergencyOnly, + @Nullable List<Integer> availableServices, @Nullable CellIdentity cellIdentity, boolean cssSupported, int roamingIndicator, int systemIsInPrl, int defaultRoamingIndicator) { - this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly, - availableServices, cellIdentity); + this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause, + emergencyOnly, availableServices, cellIdentity); mVoiceSpecificStates = new VoiceSpecificRegistrationStates(cssSupported, roamingIndicator, systemIsInPrl, defaultRoamingIndicator); @@ -224,42 +242,44 @@ public class NetworkRegistrationInfo implements Parcelable { * Constructor for data network registration info. * @hide */ - public NetworkRegistrationInfo(int domain, @TransportType int transportType, int regState, - int accessNetworkTechnology, int rejectCause, - boolean emergencyOnly, int[] availableServices, + public NetworkRegistrationInfo(int domain, @TransportType int transportType, + int registrationState, int accessNetworkTechnology, + int rejectCause, boolean emergencyOnly, + @Nullable List<Integer> availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable, LteVopsSupportInfo lteVopsSupportInfo) { - this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly, - availableServices, cellIdentity); + this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause, + emergencyOnly, availableServices, cellIdentity); mDataSpecificStates = new DataSpecificRegistrationStates( maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo); - updateNrStatus(mDataSpecificStates); + updateNrState(mDataSpecificStates); } private NetworkRegistrationInfo(Parcel source) { mDomain = source.readInt(); mTransportType = source.readInt(); - mRegState = source.readInt(); + mRegistrationState = source.readInt(); mRoamingType = source.readInt(); mAccessNetworkTechnology = source.readInt(); mRejectCause = source.readInt(); mEmergencyOnly = source.readBoolean(); - mAvailableServices = source.createIntArray(); + mAvailableServices = new ArrayList<>(); + source.readList(mAvailableServices, Integer.class.getClassLoader()); mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader()); mVoiceSpecificStates = source.readParcelable( VoiceSpecificRegistrationStates.class.getClassLoader()); mDataSpecificStates = source.readParcelable( DataSpecificRegistrationStates.class.getClassLoader()); - mNrStatus = source.readInt(); + mNrState = source.readInt(); } /** * @return The transport type. */ - public int getTransportType() { return mTransportType; } + public @TransportType int getTransportType() { return mTransportType; } /** * @return The network domain. @@ -267,23 +287,23 @@ public class NetworkRegistrationInfo implements Parcelable { public @Domain int getDomain() { return mDomain; } /** - * @return the 5G NR connection status. + * @return the 5G NR connection state. * @hide */ - public @NRStatus int getNrStatus() { - return mNrStatus; + public @NRState int getNrState() { + return mNrState; } /** @hide */ - public void setNrStatus(@NRStatus int nrStatus) { - mNrStatus = nrStatus; + public void setNrState(@NRState int nrState) { + mNrState = nrState; } /** * @return The registration state. */ - public @RegState int getRegState() { - return mRegState; + public @RegistrationState int getRegistrationState() { + return mRegistrationState; } /** @@ -298,7 +318,8 @@ public class NetworkRegistrationInfo implements Parcelable { * @return {@code true} if in service. */ public boolean isInService() { - return mRegState == REG_STATE_HOME || mRegState == REG_STATE_ROAMING; + return mRegistrationState == REGISTRATION_STATE_HOME + || mRegistrationState == REGISTRATION_STATE_ROAMING; } /** @@ -328,7 +349,9 @@ public class NetworkRegistrationInfo implements Parcelable { */ @NonNull @ServiceType - public int[] getAvailableServices() { return mAvailableServices; } + public List<Integer> getAvailableServices() { + return Collections.unmodifiableList(mAvailableServices); + } /** * @return The access network technology {@link NetworkType}. @@ -346,7 +369,7 @@ public class NetworkRegistrationInfo implements Parcelable { } /** - * @return Reason for denial if the registration state is {@link #REG_STATE_DENIED}. + * @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}. * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008 * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA */ @@ -407,28 +430,28 @@ public class NetworkRegistrationInfo implements Parcelable { * * @hide * - * @param regState The registration state + * @param registrationState The registration state * @return The reg state in string */ - public static String regStateToString(@RegState int regState) { - switch (regState) { - case REG_STATE_NOT_REG_NOT_SEARCHING: return "NOT_REG_NOT_SEARCHING"; - case REG_STATE_HOME: return "HOME"; - case REG_STATE_NOT_REG_SEARCHING: return "NOT_REG_SEARCHING"; - case REG_STATE_DENIED: return "DENIED"; - case REG_STATE_UNKNOWN: return "UNKNOWN"; - case REG_STATE_ROAMING: return "ROAMING"; + public static String registrationStateToString(@RegistrationState int registrationState) { + switch (registrationState) { + case REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING: return "NOT_REG_OR_SEARCHING"; + case REGISTRATION_STATE_HOME: return "HOME"; + case REGISTRATION_STATE_NOT_REGISTERED_SEARCHING: return "NOT_REG_SEARCHING"; + case REGISTRATION_STATE_DENIED: return "DENIED"; + case REGISTRATION_STATE_UNKNOWN: return "UNKNOWN"; + case REGISTRATION_STATE_ROAMING: return "ROAMING"; } - return "Unknown reg state " + regState; + return "Unknown reg state " + registrationState; } - private static String nrStatusToString(@NRStatus int nrStatus) { - switch (nrStatus) { - case NR_STATUS_RESTRICTED: + private static String nrStateToString(@NRState int nrState) { + switch (nrState) { + case NR_STATE_RESTRICTED: return "RESTRICTED"; - case NR_STATUS_NOT_RESTRICTED: + case NR_STATE_NOT_RESTRICTED: return "NOT_RESTRICTED"; - case NR_STATUS_CONNECTED: + case NR_STATE_CONNECTED: return "CONNECTED"; default: return "NONE"; @@ -441,28 +464,27 @@ public class NetworkRegistrationInfo implements Parcelable { .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS") .append(" transportType=").append( AccessNetworkConstants.transportTypeToString(mTransportType)) - .append(" regState=").append(regStateToString(mRegState)) + .append(" registrationState=").append(registrationStateToString(mRegistrationState)) .append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType)) .append(" accessNetworkTechnology=") .append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology)) .append(" rejectCause=").append(mRejectCause) .append(" emergencyEnabled=").append(mEmergencyOnly) .append(" availableServices=").append("[" + (mAvailableServices != null - ? Arrays.stream(mAvailableServices) - .mapToObj(type -> serviceTypeToString(type)) + ? mAvailableServices.stream().map(type -> serviceTypeToString(type)) .collect(Collectors.joining(",")) : null) + "]") .append(" cellIdentity=").append(mCellIdentity) .append(" voiceSpecificStates=").append(mVoiceSpecificStates) .append(" dataSpecificStates=").append(mDataSpecificStates) - .append(" nrStatus=").append(nrStatusToString(mNrStatus)) + .append(" nrState=").append(nrStateToString(mNrState)) .append("}").toString(); } @Override public int hashCode() { - return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType, + return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices, - mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrStatus); + mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrState); } @Override @@ -476,37 +498,37 @@ public class NetworkRegistrationInfo implements Parcelable { NetworkRegistrationInfo other = (NetworkRegistrationInfo) o; return mDomain == other.mDomain && mTransportType == other.mTransportType - && mRegState == other.mRegState + && mRegistrationState == other.mRegistrationState && mRoamingType == other.mRoamingType && mAccessNetworkTechnology == other.mAccessNetworkTechnology && mRejectCause == other.mRejectCause && mEmergencyOnly == other.mEmergencyOnly - && Arrays.equals(mAvailableServices, other.mAvailableServices) + && mAvailableServices.equals(other.mAvailableServices) && Objects.equals(mCellIdentity, other.mCellIdentity) && Objects.equals(mVoiceSpecificStates, other.mVoiceSpecificStates) && Objects.equals(mDataSpecificStates, other.mDataSpecificStates) - && mNrStatus == other.mNrStatus; + && mNrState == other.mNrState; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mDomain); dest.writeInt(mTransportType); - dest.writeInt(mRegState); + dest.writeInt(mRegistrationState); dest.writeInt(mRoamingType); dest.writeInt(mAccessNetworkTechnology); dest.writeInt(mRejectCause); dest.writeBoolean(mEmergencyOnly); - dest.writeIntArray(mAvailableServices); + dest.writeList(mAvailableServices); dest.writeParcelable(mCellIdentity, 0); dest.writeParcelable(mVoiceSpecificStates, 0); dest.writeParcelable(mDataSpecificStates, 0); - dest.writeInt(mNrStatus); + dest.writeInt(mNrState); } /** * Use the 5G NR Non-Standalone indicators from the network registration state to update the - * NR status. There are 3 indicators in the network registration state: + * NR state. There are 3 indicators in the network registration state: * * 1. if E-UTRA-NR Dual Connectivity (EN-DC) is supported by the primary serving cell. * 2. if NR is supported by the selected PLMN. @@ -521,13 +543,13 @@ public class NetworkRegistrationInfo implements Parcelable { * * @param state data specific registration state contains the 5G NR indicators. */ - private void updateNrStatus(DataSpecificRegistrationStates state) { - mNrStatus = NR_STATUS_NONE; + private void updateNrState(DataSpecificRegistrationStates state) { + mNrState = NR_STATE_NONE; if (state.isEnDcAvailable) { if (!state.isDcNrRestricted && state.isNrAvailable) { - mNrStatus = NR_STATUS_NOT_RESTRICTED; + mNrState = NR_STATE_NOT_RESTRICTED; } else { - mNrStatus = NR_STATUS_RESTRICTED; + mNrState = NR_STATE_RESTRICTED; } } } @@ -571,40 +593,31 @@ public class NetworkRegistrationInfo implements Parcelable { * * <pre><code> * - * NetworkRegistrationInfo nrs = new NetworkRegistrationInfo.Builder() - * .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS) - * .setApnName("apn.example.com") - * .setEntryName("Example Carrier APN") - * .setMmsc(Uri.parse("http://mms.example.com:8002")) - * .setMmsProxyAddress(mmsProxy) - * .setMmsProxyPort(8799) + * NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + * .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + * .setRegistrationState(REGISTRATION_STATE_HOME) * .build(); * </code></pre> */ - public static class Builder{ + public static final class Builder{ @Domain private int mDomain; + @TransportType private int mTransportType; - @RegState - private int mRegState; - - @ServiceState.RoamingType - private int mRoamingType; + @RegistrationState + private int mRegistrationState; @NetworkType private int mAccessNetworkTechnology; - @NRStatus - private int mNrStatus; - private int mRejectCause; private boolean mEmergencyOnly; @ServiceType - private int[] mAvailableServices; + private List<Integer> mAvailableServices; @Nullable private CellIdentity mCellIdentity; @@ -641,24 +654,12 @@ public class NetworkRegistrationInfo implements Parcelable { /** * Set the registration state. * - * @param regState The registration state. + * @param registrationState The registration state. * * @return The same instance of the builder. */ - public @NonNull Builder setRegState(@RegState int regState) { - mRegState = regState; - return this; - } - - /** - * Set the roaming type. - * - * @param roamingType Roaming type. - * - * @return The same instance of the builder. - */ - public @NonNull Builder setRoamingType(@ServiceState.RoamingType int roamingType) { - mRoamingType = roamingType; + public @NonNull Builder setRegistrationState(@RegistrationState int registrationState) { + mRegistrationState = registrationState; return this; } @@ -676,24 +677,13 @@ public class NetworkRegistrationInfo implements Parcelable { } /** - * Set the 5G NR connection status. - * - * @param nrStatus 5G NR connection status. - * - * @return The same instance of the builder. - */ - public @NonNull Builder setNrStatus(@NRStatus int nrStatus) { - mNrStatus = nrStatus; - return this; - } - - /** * Set the network reject cause. * * @param rejectCause Reason for denial if the registration state is - * {@link #REG_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the values are - * defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 - * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0. + * {@link #REGISTRATION_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the + * values are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, + * and 3GPP2 A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set + * it to 0. * * @return The same instance of the builder. */ @@ -722,7 +712,7 @@ public class NetworkRegistrationInfo implements Parcelable { * @return The same instance of the builder. */ public @NonNull Builder setAvailableServices( - @NonNull @ServiceType int[] availableServices) { + @NonNull @ServiceType List<Integer> availableServices) { mAvailableServices = availableServices; return this; } @@ -745,7 +735,7 @@ public class NetworkRegistrationInfo implements Parcelable { * @return the NetworkRegistrationInfo object. */ public @NonNull NetworkRegistrationInfo build() { - return new NetworkRegistrationInfo(mDomain, mTransportType, mRegState, + return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity); } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index adbe295513a7..30dcaa0091d2 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -30,7 +30,7 @@ import android.os.Parcelable; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.AccessNetworkConstants.TransportType; import android.telephony.NetworkRegistrationInfo.Domain; -import android.telephony.NetworkRegistrationInfo.NRStatus; +import android.telephony.NetworkRegistrationInfo.NRState; import android.text.TextUtils; import java.lang.annotation.Retention; @@ -53,6 +53,9 @@ import java.util.stream.Collectors; * <li>Operator name, short name and numeric id * <li>Network selection mode * </ul> + * + * For historical reasons this class is not declared as final; however, + * it should be treated as though it were final. */ public class ServiceState implements Parcelable { @@ -647,7 +650,8 @@ public class ServiceState implements Parcelable { final NetworkRegistrationInfo regState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (regState != null) { - return (regState.getRegState() == NetworkRegistrationInfo.REG_STATE_ROAMING); + return regState.getRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; } return false; } @@ -1133,10 +1137,10 @@ public class ServiceState implements Parcelable { NetworkRegistrationInfo regState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (regState == null) { - regState = new NetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, - false, null, null); + regState = new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_CS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .build(); addNetworkRegistrationInfo(regState); } regState.setRoamingType(type); @@ -1154,10 +1158,10 @@ public class ServiceState implements Parcelable { NetworkRegistrationInfo regState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (regState == null) { - regState = new NetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, - false, null, null); + regState = new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .build(); addNetworkRegistrationInfo(regState); } regState.setRoamingType(type); @@ -1329,10 +1333,10 @@ public class ServiceState implements Parcelable { NetworkRegistrationInfo regState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (regState == null) { - regState = new NetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, - 0, false, null, null); + regState = new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_CS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .build(); addNetworkRegistrationInfo(regState); } regState.setAccessNetworkTechnology( @@ -1357,10 +1361,10 @@ public class ServiceState implements Parcelable { NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (regState == null) { - regState = new NetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, - 0, false, null, null); + regState = new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .build(); addNetworkRegistrationInfo(regState); } regState.setAccessNetworkTechnology( @@ -1386,15 +1390,15 @@ public class ServiceState implements Parcelable { } /** - * Get the NR 5G status of the mobile data network. - * @return the NR 5G status. + * Get the NR 5G state of the mobile data network. + * @return the NR 5G state. * @hide */ - public @NRStatus int getNrStatus() { + public @NRState int getNrState() { final NetworkRegistrationInfo regState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (regState == null) return NetworkRegistrationInfo.NR_STATUS_NONE; - return regState.getNrStatus(); + if (regState == null) return NetworkRegistrationInfo.NR_STATE_NONE; + return regState.getNrState(); } /** @@ -1578,8 +1582,8 @@ public class ServiceState implements Parcelable { public @TelephonyManager.NetworkType int getDataNetworkType() { final NetworkRegistrationInfo iwlanRegState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - if (iwlanRegState != null - && iwlanRegState.getRegState() == NetworkRegistrationInfo.REG_STATE_HOME) { + if (iwlanRegState != null && iwlanRegState.getRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { // If the device is on IWLAN, return IWLAN as the network type. This is to simulate the // behavior of legacy mode device. In the future caller should use // getNetworkRegistrationInfo() to retrieve the actual data network type on cellular diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 245f5b3a9eac..ac1194089758 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -161,11 +161,6 @@ public class SubscriptionInfo implements Parcelable { private String mGroupUUID; /** - * A property in opportunistic subscription to indicate whether it is metered or not. - */ - private boolean mIsMetered; - - /** * Whether group of the subscription is disabled. * This is only useful if it's a grouped opportunistic subscription. In this case, if all * primary (non-opportunistic) subscriptions in the group are deactivated (unplugged pSIM @@ -197,7 +192,7 @@ public class SubscriptionInfo implements Parcelable { @Nullable UiccAccessRule[] accessRules, String cardString) { this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, - false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID, + false, null, TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT); } @@ -208,10 +203,10 @@ public class SubscriptionInfo implements Parcelable { CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic, - @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) { + @Nullable String groupUUID, int carrierId, int profileClass) { this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1, - isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass, + isOpportunistic, groupUUID, false, carrierId, profileClass, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); } @@ -222,7 +217,7 @@ public class SubscriptionInfo implements Parcelable { CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] accessRules, String cardString, int cardId, - boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered, + boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled, int carrierId, int profileClass, int subType) { this.mId = id; this.mIccId = iccId; @@ -243,7 +238,6 @@ public class SubscriptionInfo implements Parcelable { this.mCardId = cardId; this.mIsOpportunistic = isOpportunistic; this.mGroupUUID = groupUUID; - this.mIsMetered = isMetered; this.mIsGroupDisabled = isGroupDisabled; this.mCarrierId = carrierId; this.mProfileClass = profileClass; @@ -472,18 +466,6 @@ public class SubscriptionInfo implements Parcelable { } /** - * Used in opportunistic subscription ({@link #isOpportunistic()}) to indicate whether it's - * metered or not.This is one of the factors when deciding to switch to the subscription. - * (a non-metered subscription, for example, would likely be preferred over a metered one). - * - * @return whether subscription is metered. - * @hide - */ - public boolean isMetered() { - return mIsMetered; - } - - /** * @return the profile class of this subscription. * @hide */ @@ -624,7 +606,6 @@ public class SubscriptionInfo implements Parcelable { int cardId = source.readInt(); boolean isOpportunistic = source.readBoolean(); String groupUUID = source.readString(); - boolean isMetered = source.readBoolean(); boolean isGroupDisabled = source.readBoolean(); int carrierid = source.readInt(); int profileClass = source.readInt(); @@ -633,7 +614,7 @@ public class SubscriptionInfo implements Parcelable { return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID, - isMetered, isGroupDisabled, carrierid, profileClass, subType); + isGroupDisabled, carrierid, profileClass, subType); } @Override @@ -663,7 +644,6 @@ public class SubscriptionInfo implements Parcelable { dest.writeInt(mCardId); dest.writeBoolean(mIsOpportunistic); dest.writeString(mGroupUUID); - dest.writeBoolean(mIsMetered); dest.writeBoolean(mIsGroupDisabled); dest.writeInt(mCarrierId); dest.writeInt(mProfileClass); @@ -703,7 +683,7 @@ public class SubscriptionInfo implements Parcelable { + " accessRules " + Arrays.toString(mAccessRules) + " cardString=" + cardStringToPrint + " cardId=" + mCardId + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID - + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled + + " mIsGroupDisabled=" + mIsGroupDisabled + " profileClass=" + mProfileClass + " subscriptionType=" + mSubscriptionType + "}"; } @@ -711,7 +691,7 @@ public class SubscriptionInfo implements Parcelable { @Override public int hashCode() { return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded, - mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc, + mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules, mIsGroupDisabled, mCarrierId, mProfileClass); } @@ -737,7 +717,6 @@ public class SubscriptionInfo implements Parcelable { && mIsOpportunistic == toCompare.mIsOpportunistic && mIsGroupDisabled == toCompare.mIsGroupDisabled && mCarrierId == toCompare.mCarrierId - && mIsMetered == toCompare.mIsMetered && Objects.equals(mGroupUUID, toCompare.mGroupUUID) && Objects.equals(mIccId, toCompare.mIccId) && Objects.equals(mNumber, toCompare.mNumber) diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 3707aa43f372..2edef838ff28 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2595,7 +2595,9 @@ public class SubscriptionManager { * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means * it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()} * is used to determine which modem is preferred. - * @param needValidation whether validation is needed before switch happens. + * @param needValidation whether Telephony will wait until the network is validated by + * connectivity service before switching data to it. More details see + * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. * @param executor The executor of where the callback will execute. * @param callback Callback will be triggered once it succeeds or failed. * See {@link TelephonyManager.SetOpportunisticSubscriptionResult} @@ -2853,29 +2855,6 @@ public class SubscriptionManager { } /** - * Set if a subscription is metered or not. Similar to Wi-Fi, metered means - * user may be charged more if more data is used. - * - * By default all Cellular networks are considered metered. System or carrier privileged apps - * can set a subscription un-metered which will be considered when system switches data between - * primary subscription and opportunistic subscription. - * - * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier - * privilege permission of the subscription. - * - * @param isMetered whether it’s a metered subscription. - * @param subId the unique SubscriptionInfo index in database - * @return {@code true} if the operation is succeed, {@code false} otherwise. - */ - @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges - @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - public boolean setMetered(boolean isMetered, int subId) { - if (VDBG) logd("[setIsMetered]+ isMetered:" + isMetered + " subId:" + subId); - return setSubscriptionPropertyHelper(subId, "setIsMetered", - (iSub)-> iSub.setMetered(isMetered, subId, mContext.getOpPackageName())) == 1; - } - - /** * Whether a subscription is visible to API caller. If it's a bundled opportunistic * subscription, it should be hidden anywhere in Settings, dialer, status bar etc. * Exception is if caller owns carrier privilege, in which case they will diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 66ef531c2cfe..282b1ff2f801 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -4779,18 +4779,22 @@ public class TelephonyManager { * Registers a listener object to receive notification of changes * in specified telephony states. * <p> - * To register a listener, pass a {@link PhoneStateListener} - * and specify at least one telephony state of interest in - * the events argument. - * - * At registration, and when a specified telephony state - * changes, the telephony manager invokes the appropriate - * callback method on the listener object and passes the - * current (updated) values. + * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony + * state of interest in the events argument. + * + * At registration, and when a specified telephony state changes, the telephony manager invokes + * the appropriate callback method on the listener object and passes the current (updated) + * values. * <p> - * To unregister a listener, pass the listener object and set the - * events argument to + * To un-register a listener, pass the listener object and set the events argument to * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0). + * + * If this TelephonyManager object has been created with {@link #createForSubscriptionId}, + * applies to the given subId. Otherwise, applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds, + * pass a separate listener object to each TelephonyManager object created with + * {@link #createForSubscriptionId}. + * * Note: if you call this method while in the middle of a binder transaction, you <b>must</b> * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A * {@link SecurityException} will be thrown otherwise. @@ -4805,17 +4809,18 @@ public class TelephonyManager { if (mContext == null) return; try { boolean notifyNow = (getITelephony() != null); - // If the listener has not explicitly set the subId (for example, created with the - // default constructor), replace the subId so it will listen to the account the - // telephony manager is created with. - if (listener.mSubId == null) { - listener.mSubId = mSubId; - } - ITelephonyRegistry registry = getTelephonyRegistry(); if (registry != null) { - registry.listenForSubscriber(listener.mSubId, getOpPackageName(), + // listen to the subId the telephony manager is created with. Ignore subId in + // PhoneStateListener. + registry.listenForSubscriber(mSubId, getOpPackageName(), listener.callback, events, notifyNow); + // TODO: remove this once we remove PhoneStateListener constructor with subId. + if (events == PhoneStateListener.LISTEN_NONE) { + listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } else { + listener.mSubId = mSubId; + } } else { Rlog.w(TAG, "telephony registry not ready."); } @@ -8293,7 +8298,7 @@ public class TelephonyManager { * @see SubscriptionManager#getDefaultSubscriptionId() * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage public boolean isVolteAvailable() { try { return getITelephony().isAvailable(getSubId(), @@ -8312,7 +8317,7 @@ public class TelephonyManager { * @return true if VT is available, or false if it is unavailable or unknown. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage public boolean isVideoTelephonyAvailable() { try { return getITelephony().isVideoTelephonyAvailable(getSubId()); @@ -8327,7 +8332,7 @@ public class TelephonyManager { * @return true if VoWiFi is available, or false if it is unavailable or unknown. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage public boolean isWifiCallingAvailable() { try { return getITelephony().isWifiCallingAvailable(getSubId()); @@ -9865,8 +9870,11 @@ public class TelephonyManager { * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} * + * + * @deprecated * @hide */ + @Deprecated @TestApi public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1, String gid2, String plmn, String spn) { @@ -9874,7 +9882,35 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony != null) { telephony.setCarrierTestOverride( - getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn); + getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn, + null, null); + } + } catch (RemoteException ex) { + // This could happen if binder process crashes. + } + } + + /** + * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2, + * plmn, spn, apn and carrier priviledge. This would be handy for, eg, forcing a particular + * carrier id, carrier's config (also any country or carrier overlays) to be loaded when using + * a test SIM with a call box. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * + * @hide + */ + @TestApi + public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1, + String gid2, String plmn, String spn, + String carrierPriviledgeRules, String apn) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.setCarrierTestOverride( + getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn, + carrierPriviledgeRules, apn); } } catch (RemoteException ex) { // This could happen if binder process crashes. @@ -10337,7 +10373,7 @@ public class TelephonyManager { @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = { SET_OPPORTUNISTIC_SUB_SUCCESS, SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED, - SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER}) + SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION}) public @interface SetOpportunisticSubscriptionResult {} /** @@ -10351,9 +10387,9 @@ public class TelephonyManager { public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; /** - * The parameter passed in is invalid. + * The subscription is not valid. It must be an active opportunistic subscription. */ - public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; + public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; /** @hide */ @Retention(RetentionPolicy.SOURCE) diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index e651783c44f2..875bd782d2cb 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -285,6 +285,8 @@ public class EuiccManager { * {@link #ACTION_DELETE_SUBSCRIPTION_PRIVILEGED}, and * {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing the ID of the targeted subscription. * + * <p>Expected type of the extra data: int + * * @hide */ @SystemApi @@ -295,6 +297,8 @@ public class EuiccManager { * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing a boolean * value of whether to enable or disable the targeted subscription. * + * <p>Expected type of the extra data: boolean + * * @hide */ @SystemApi @@ -305,6 +309,8 @@ public class EuiccManager { * Key for an extra set on {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing a new * nickname for the targeted subscription. * + * <p>Expected type of the extra data: String + * * @hide */ @SystemApi diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 79e0aa15b6ab..3bbf7a41eebf 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -205,15 +205,6 @@ interface ISub { String setSubscriptionGroup(in int[] subIdList, String callingPackage); /** - * Set whether a subscription is metered - * - * @param isMetered whether it’s a metered subscription. - * @param subId the unique SubscriptionInfo index in database - * @return the number of records updated - */ - int setMetered(boolean isMetered, int subId, String callingPackage); - - /** * Set which subscription is preferred for cellular data. It's * designed to overwrite default data subscription temporarily. * diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 62b92fd9a789..c2c31ccee795 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1683,7 +1683,7 @@ interface ITelephony { * (also any country or carrier overlays) to be loaded when using a test SIM with a call box. */ void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1, - String gid2, String plmn, String spn); + String gid2, String plmn, String spn, String carrierPrivilegeRules, String apn); /** * A test API to return installed carrier id list version. diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index 9d78bf4bfb53..4886a3f8f141 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -317,7 +317,8 @@ public final class TelephonyPermissions { Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED, 0) == 1; ApplicationInfo callingPackageInfo = null; try { - callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0); + callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser( + callingPackage, 0, UserHandle.getUserId(uid)); if (callingPackageInfo.isSystemApp()) { isPreinstalled = true; if (callingPackageInfo.isPrivilegedApp()) { diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index b31235be8373..41cb74af911c 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -4,7 +4,7 @@ --> <configuration description="Runs WindowManager Flicker Tests"> <option name="test-tag" value="FlickerTests" /> - <target_preparer class="com.google.android.tradefed.targetprep.GoogleDeviceSetup"> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> <!-- keeps the screen on during tests --> <option name="screen-always-on" value="on" /> <!-- prevents the phone from restarting --> diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java index 8a925b9bad38..ebe54187ddb6 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java @@ -63,6 +63,13 @@ class RollbackBroadcastReceiver extends BroadcastReceiver { } /** + * Waits forever for the next rollback broadcast. + */ + Intent take() throws InterruptedException { + return mRollbackBroadcasts.take(); + } + + /** * Unregisters this broadcast receiver. */ void unregister() { diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index 7505230e69c6..52919df1cf0a 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -27,7 +27,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import android.Manifest; -import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -46,8 +45,6 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.Collections; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** @@ -87,6 +84,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, + Manifest.permission.TEST_MANAGE_ROLLBACKS, Manifest.permission.MANAGE_ROLLBACKS); // Register a broadcast receiver for notification when the @@ -175,7 +173,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackManager rm = RollbackTestUtils.getRollbackManager(); @@ -233,7 +231,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackManager rm = RollbackTestUtils.getRollbackManager(); @@ -290,7 +288,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackManager rm = RollbackTestUtils.getRollbackManager(); @@ -343,11 +341,11 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.TEST_MANAGE_ROLLBACKS, Manifest.permission.WRITE_DEVICE_CONFIG); - DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE, - DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT, + RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS, Long.toString(expirationTime), false /* makeDefault*/); // Pull the new expiration time from DeviceConfig @@ -382,8 +380,8 @@ public class RollbackTest { assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); } finally { - DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE, - DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT, + RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS, Long.toString(defaultExpirationTime), false /* makeDefault*/); RollbackTestUtils.dropShellPermissionIdentity(); } @@ -403,12 +401,12 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.TEST_MANAGE_ROLLBACKS, Manifest.permission.WRITE_DEVICE_CONFIG, Manifest.permission.SET_TIME); - DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE, - DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT, + RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS, Long.toString(expirationTime), false /* makeDefault*/); // Pull the new expiration time from DeviceConfig @@ -458,8 +456,8 @@ public class RollbackTest { RollbackTestUtils.forwardTimeBy(-expirationTime); } } finally { - DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE, - DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT, + RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS, Long.toString(defaultExpirationTime), false /* makeDefault*/); RollbackTestUtils.dropShellPermissionIdentity(); } @@ -475,7 +473,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackManager rm = RollbackTestUtils.getRollbackManager(); RollbackTestUtils.uninstall(TEST_APP_A); @@ -512,7 +510,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackTestUtils.uninstall(TEST_APP_A); RollbackTestUtils.install("RollbackTestAppAv1.apk", false); @@ -540,7 +538,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackTestUtils.uninstall(TEST_APP_A); RollbackTestUtils.installSplit(false, @@ -598,7 +596,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackManager rm = RollbackTestUtils.getRollbackManager(); // Prep installation of the test apps. @@ -693,6 +691,75 @@ public class RollbackTest { } /** + * Test that you cannot enable rollback for a package without the + * MANAGE_ROLLBACKS permission. + */ + @Test + public void testEnableRollbackPermission() throws Exception { + try { + RollbackTestUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES); + + RollbackTestUtils.uninstall(TEST_APP_A); + RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false); + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true); + + // We expect v2 of the app was installed, but rollback has not + // been enabled. + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + // TODO: See if there is a way to remove this race condition + // between when the app is installed and when the rollback + // would be made available. + Thread.sleep(1000); + + RollbackTestUtils.adoptShellPermissionIdentity( + Manifest.permission.TEST_MANAGE_ROLLBACKS); + RollbackManager rm = RollbackTestUtils.getRollbackManager(); + assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + } finally { + RollbackTestUtils.dropShellPermissionIdentity(); + } + } + + /** + * Test that you cannot enable rollback for a non-module package when + * holding the MANAGE_ROLLBACKS permission. + */ + @Test + public void testNonModuleEnableRollback() throws Exception { + try { + RollbackTestUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.MANAGE_ROLLBACKS); + + RollbackTestUtils.uninstall(TEST_APP_A); + RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false); + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true); + + // We expect v2 of the app was installed, but rollback has not + // been enabled because the test app is not a module. + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + // TODO: See if there is a way to remove this race condition + // between when the app is installed and when the rollback + // would be made available. + Thread.sleep(1000); + + RollbackManager rm = RollbackTestUtils.getRollbackManager(); + assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + } finally { + RollbackTestUtils.dropShellPermissionIdentity(); + } + } + + /** * Test rollback of multi-package installs is implemented. */ @Test @@ -701,7 +768,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); RollbackManager rm = RollbackTestUtils.getRollbackManager(); // Prep installation of the test apps. @@ -760,7 +827,7 @@ public class RollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.TEST_MANAGE_ROLLBACKS, Manifest.permission.KILL_BACKGROUND_PROCESSES, Manifest.permission.RESTART_PACKAGES); RollbackManager rm = RollbackTestUtils.getRollbackManager(); @@ -790,34 +857,14 @@ public class RollbackTest { rm.getAvailableRollbacks(), TEST_APP_B); assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB); - BlockingQueue<Integer> crashQueue = new SynchronousQueue<>(); - - IntentFilter crashCountFilter = new IntentFilter(); - crashCountFilter.addAction("com.android.tests.rollback.CRASH"); - crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT); - - crashCountReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - try { - // Sleep long enough for packagewatchdog to be notified of crash - Thread.sleep(1000); - // Kill app and close AppErrorDialog - ActivityManager am = context.getSystemService(ActivityManager.class); - am.killBackgroundProcesses(TEST_APP_A); - // Allow another package launch - crashQueue.put(intent.getIntExtra("count", 0)); - } catch (InterruptedException e) { - fail("Failed to communicate with test app"); - } - } - }; - context.registerReceiver(crashCountReceiver, crashCountFilter); - - // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes - do { - RollbackTestUtils.launchPackage(TEST_APP_A); - } while(crashQueue.take() < 5); + // Register rollback committed receiver + RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver(); + + // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback + crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5); + + // Verify we received a broadcast for the rollback. + rollbackReceiver.take(); // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java index 9aed0748266a..81629aaaec76 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import android.app.ActivityManager; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -47,6 +48,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SynchronousQueue; /** * Utilities to facilitate testing rollbacks. @@ -187,7 +189,7 @@ class RollbackTestUtils { } /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */ - static void launchPackage(String packageName) + private static void launchPackage(String packageName) throws InterruptedException, IOException { Context context = InstrumentationRegistry.getContext(); Intent intent = new Intent(Intent.ACTION_MAIN); @@ -488,4 +490,39 @@ class RollbackTestUtils { } return null; } + + /** + * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least + * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered. + */ + static BroadcastReceiver sendCrashBroadcast(Context context, String packageName, int count) + throws InterruptedException, IOException { + BlockingQueue<Integer> crashQueue = new SynchronousQueue<>(); + IntentFilter crashCountFilter = new IntentFilter(); + crashCountFilter.addAction("com.android.tests.rollback.CRASH"); + crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT); + + BroadcastReceiver crashCountReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + try { + // Sleep long enough for packagewatchdog to be notified of crash + Thread.sleep(1000); + // Kill app and close AppErrorDialog + ActivityManager am = context.getSystemService(ActivityManager.class); + am.killBackgroundProcesses(packageName); + // Allow another package launch + crashQueue.put(intent.getIntExtra("count", 0)); + } catch (InterruptedException e) { + fail("Failed to communicate with test app"); + } + } + }; + context.registerReceiver(crashCountReceiver, crashCountFilter); + + do { + launchPackage(packageName); + } while(crashQueue.take() < count); + return crashCountReceiver; + } } diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java index 047451b643da..7e711c290e5a 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java @@ -63,7 +63,7 @@ public class StagedRollbackTest { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, - Manifest.permission.MANAGE_ROLLBACKS); + Manifest.permission.TEST_MANAGE_ROLLBACKS); } /** diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 2539c0f66ce1..c62d85e4187e 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -13,7 +13,6 @@ android_test { "mockito-target-minus-junit4", "platform-test-annotations", "services.core", - "services.ipmemorystore", "services.net", ], libs: [ diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java index 9ede2b85af00..975abf416944 100644 --- a/tests/net/java/android/net/DnsPacketTest.java +++ b/tests/net/java/android/net/DnsPacketTest.java @@ -69,7 +69,7 @@ public class DnsPacketTest { try { new TestDnsPacket(null); fail("Exception not thrown for null byte array"); - } catch (DnsPacket.ParseException e) { + } catch (ParseException e) { } } diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java index 57ecc8f38c69..18c67688940a 100644 --- a/tests/net/java/android/net/IpMemoryStoreTest.java +++ b/tests/net/java/android/net/IpMemoryStoreTest.java @@ -16,6 +16,9 @@ package android.net; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; + import android.content.Context; import androidx.test.filters.SmallTest; @@ -33,13 +36,25 @@ public class IpMemoryStoreTest { @Mock Context mMockContext; @Mock + NetworkStackClient mNetworkStackClient; + @Mock IIpMemoryStore mMockService; IpMemoryStore mStore; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mStore = new IpMemoryStore(mMockContext, mMockService); + doAnswer(invocation -> { + ((IIpMemoryStoreCallbacks) invocation.getArgument(0)) + .onIpMemoryStoreFetched(mMockService); + return null; + }).when(mNetworkStackClient).fetchIpMemoryStore(any()); + mStore = new IpMemoryStore(mMockContext) { + @Override + protected NetworkStackClient getNetworkStackClient() { + return mNetworkStackClient; + } + }; } @Test diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java new file mode 100644 index 000000000000..75752c33da5c --- /dev/null +++ b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java @@ -0,0 +1,50 @@ +/* + * 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 android.net.apf; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.net.shared.ParcelableTestUtil; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.TestUtils; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ApfCapabilitiesTest { + @Test + public void testParcelUnparcel() { + final ApfCapabilities caps = new ApfCapabilities(123, 456, 789); + ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class); + + TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR); + } + + @Test + public void testEquals() { + assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3)); + assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3)); + assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3)); + assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3)); + } +} diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java index 830c928d1e7f..9b4f49c6248f 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java @@ -101,6 +101,7 @@ public class NetworkStatsCollectionTest { @After public void tearDown() throws Exception { RecurrenceRule.sClock = sOriginalClock; + NetworkTemplate.resetForceAllNetworkTypes(); } private void setClock(Instant instant) { diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 598448b3e1b1..bce526d3ae29 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -19,6 +19,7 @@ package com.android.server.net; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -41,6 +42,7 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; +import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.UID_REMOVED; @@ -132,6 +134,8 @@ public class NetworkStatsServiceTest { private static final String TEST_IFACE = "test0"; private static final String TEST_IFACE2 = "test1"; + private static final String TUN_IFACE = "test_nss_tun0"; + private static final long TEST_START = 1194220800000L; private static final String IMSI_1 = "310004"; @@ -145,10 +149,12 @@ public class NetworkStatsServiceTest { private static final int UID_RED = 1001; private static final int UID_BLUE = 1002; private static final int UID_GREEN = 1003; - + private static final int UID_VPN = 1004; private static final Network WIFI_NETWORK = new Network(100); private static final Network MOBILE_NETWORK = new Network(101); + private static final Network VPN_NETWORK = new Network(102); + private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK }; private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK }; @@ -914,7 +920,113 @@ public class NetworkStatsServiceTest { assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0); assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0); assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0); + } + + @Test + public void vpnWithOneUnderlyingIface() throws Exception { + // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). + expectDefaultSettings(); + NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. + // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN. + // VPN sent/received 1650 bytes (150 packets) over WiFi. + // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to + // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) + .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L) + .addValues( + TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 1650L, 150L, 2L)); + forcePollAndWaitForIdle(); + + assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1); + assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2); + } + + @Test + public void vpnWithOneUnderlyingIface_withCompression() throws Exception { + // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). + expectDefaultSettings(); + NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. + // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN. + // VPN sent/received 1000 bytes (100 packets) over WiFi. + // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE, + // with nothing attributed to UID_VPN for both rx/tx traffic. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) + .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 3000L, 300L, 3000L, 300L, 1L) + .addValues( + TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 0L)); + + forcePollAndWaitForIdle(); + + assertUidTotal(sTemplateWifi, UID_RED, 250L, 25L, 250L, 25L, 0); + assertUidTotal(sTemplateWifi, UID_BLUE, 750L, 75L, 750L, 75L, 0); + assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0); + } + + @Test + public void vpnWithIncorrectUnderlyingIface() throws Exception { + // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2), + // but has declared only WiFi (TEST_IFACE) in its underlying network set. + expectDefaultSettings(); + NetworkState[] networkStates = + new NetworkState[] { + buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() + }; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. + // VPN sent/received 1100 bytes (100 packets) over Cell. + // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) + .addValues( + TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 1100L, 100L, 1L)); + + forcePollAndWaitForIdle(); + + assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0); + assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0); + assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 0L, 0L, 0L, 0L, 0); + assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1); } @Test @@ -1262,6 +1374,22 @@ public class NetworkStatsServiceTest { return new NetworkStats(getElapsedRealtime(), 0); } + private static NetworkState buildVpnState() { + final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null); + info.setDetailedState(DetailedState.CONNECTED, null, null); + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(TUN_IFACE); + return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null); + } + + private static VpnInfo createVpnInfo(String underlyingIface) { + VpnInfo info = new VpnInfo(); + info.ownerUid = UID_VPN; + info.vpnIface = TUN_IFACE; + info.primaryUnderlyingIface = underlyingIface; + return info; + } + private long getElapsedRealtime() { return mElapsedRealtime; } diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index 5cf056e60640..7ded9bcf8470 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -32,6 +32,7 @@ class DumpApkCommand : public Command { public: explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag) : Command(name), printer_(printer), diag_(diag) { + SetDescription("Dump information about an APK or APC."); } text::Printer* GetPrinter() { diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index e9375176f26b..a24e0d2f93d0 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -58,7 +58,7 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overla // valid. This is because un-mangled references are mangled, then looked up at resolution // time. Also, when linking, we convert references with no package name to use the compilation // package name. - error |= !DoMerge(src, table, package.get(), false /*mangle*/, overlay, allow_new); + error |= !DoMerge(src, package.get(), false /*mangle*/, overlay, allow_new); } } return !error; @@ -78,7 +78,7 @@ bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_n bool mangle = package_name != context_->GetCompilationPackage(); merged_packages_.insert(package->name); - error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/); + error |= !DoMerge(src, package.get(), mangle, false /*overlay*/, true /*allow_new*/); } return !error; } @@ -213,9 +213,8 @@ static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context, return collision_result; } -bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table, - ResourceTablePackage* src_package, bool mangle_package, bool overlay, - bool allow_new_resources) { +bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package, + bool overlay, bool allow_new_resources) { bool error = false; for (auto& src_type : src_package->types) { @@ -337,8 +336,7 @@ bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFi ->FindOrCreateValue(file_desc.config, {}) ->value = std::move(file_ref); - return DoMerge(file->GetSource(), &table, pkg, false /*mangle*/, overlay /*overlay*/, - true /*allow_new*/); + return DoMerge(file->GetSource(), pkg, false /*mangle*/, overlay /*overlay*/, true /*allow_new*/); } } // namespace aapt diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h index 24c5e1329244..51305cfcdd25 100644 --- a/tools/aapt2/link/TableMerger.h +++ b/tools/aapt2/link/TableMerger.h @@ -85,8 +85,8 @@ class TableMerger { bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new); - bool DoMerge(const Source& src, ResourceTable* src_table, ResourceTablePackage* src_package, - bool mangle_package, bool overlay, bool allow_new_resources); + bool DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package, + bool overlay, bool allow_new_resources); std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package, const FileReference& value); diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java index 2042a68857fb..7f5f9ca8a8f8 100644 --- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java +++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java @@ -635,14 +635,14 @@ public final class InspectablePropertyProcessor implements ModelProcessor { final String name = mAnnotationUtils.typedValueByName( "name", String.class, accessor, enumAnnotation) .orElseThrow(() -> new ProcessingException( - "Name is required for @EnumMap", + "Name is required for @EnumEntry", accessor, enumAnnotation)); final int value = mAnnotationUtils.typedValueByName( "value", Integer.class, accessor, enumAnnotation) .orElseThrow(() -> new ProcessingException( - "Value is required for @EnumMap", + "Value is required for @EnumEntry", accessor, enumAnnotation)); @@ -684,14 +684,14 @@ public final class InspectablePropertyProcessor implements ModelProcessor { final String name = mAnnotationUtils.typedValueByName( "name", String.class, accessor, flagAnnotation) .orElseThrow(() -> new ProcessingException( - "Name is required for @FlagMap", + "Name is required for @FlagEntry", accessor, flagAnnotation)); final int target = mAnnotationUtils.typedValueByName( "target", Integer.class, accessor, flagAnnotation) .orElseThrow(() -> new ProcessingException( - "Target is required for @FlagMap", + "Target is required for @FlagEntry", accessor, flagAnnotation)); diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java index 51aa93a1c4c7..01176f223fe2 100644 --- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java +++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.TelephonyManager.NetworkType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -98,6 +99,10 @@ public final class WifiUsabilityStatsEntry implements Parcelable { private final int mProbeMcsRateSinceLastUpdate; /** Rx link speed at the sample time in Mbps */ private final int mRxLinkSpeedMbps; + private final @NetworkType int mCellularDataNetworkType; + private final int mCellularSignalStrengthDbm; + private final int mCellularSignalStrengthDb; + private final boolean mIsSameRegisteredCell; /** Constructor function {@hide} */ public WifiUsabilityStatsEntry(long timeStampMillis, int rssi, int linkSpeedMbps, @@ -109,7 +114,10 @@ public final class WifiUsabilityStatsEntry implements Parcelable { long totalHotspot2ScanTimeMillis, long totalCcaBusyFreqTimeMillis, long totalRadioOnFreqTimeMillis, long totalBeaconRx, @ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeSinceLastUpdateMillis, - int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps) { + int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps, + @NetworkType int cellularDataNetworkType, + int cellularSignalStrengthDbm, int cellularSignalStrengthDb, + boolean isSameRegisteredCell) { mTimeStampMillis = timeStampMillis; mRssi = rssi; mLinkSpeedMbps = linkSpeedMbps; @@ -133,6 +141,10 @@ public final class WifiUsabilityStatsEntry implements Parcelable { mProbeElapsedTimeSinceLastUpdateMillis = probeElapsedTimeSinceLastUpdateMillis; mProbeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate; mRxLinkSpeedMbps = rxLinkSpeedMbps; + mCellularDataNetworkType = cellularDataNetworkType; + mCellularSignalStrengthDbm = cellularSignalStrengthDbm; + mCellularSignalStrengthDb = cellularSignalStrengthDb; + mIsSameRegisteredCell = isSameRegisteredCell; } /** Implement the Parcelable interface */ @@ -165,6 +177,10 @@ public final class WifiUsabilityStatsEntry implements Parcelable { dest.writeInt(mProbeElapsedTimeSinceLastUpdateMillis); dest.writeInt(mProbeMcsRateSinceLastUpdate); dest.writeInt(mRxLinkSpeedMbps); + dest.writeInt(mCellularDataNetworkType); + dest.writeInt(mCellularSignalStrengthDbm); + dest.writeInt(mCellularSignalStrengthDb); + dest.writeBoolean(mIsSameRegisteredCell); } /** Implement the Parcelable interface */ @@ -179,7 +195,9 @@ public final class WifiUsabilityStatsEntry implements Parcelable { in.readLong(), in.readLong(), in.readLong(), in.readLong(), in.readLong(), in.readLong(), in.readLong(), in.readLong(), in.readInt(), - in.readInt(), in.readInt(), in.readInt() + in.readInt(), in.readInt(), in.readInt(), + in.readInt(), in.readInt(), in.readInt(), + in.readBoolean() ); } @@ -304,4 +322,30 @@ public final class WifiUsabilityStatsEntry implements Parcelable { public int getRxLinkSpeedMbps() { return mRxLinkSpeedMbps; } + + /** Cellular data network type currently in use on the device for data transmission */ + @NetworkType public int getCellularDataNetworkType() { + return mCellularDataNetworkType; + } + + /** + * Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp, + * CDMA: Rssi, EVDO: Rssi, GSM: Rssi + */ + public int getCellularSignalStrengthDbm() { + return mCellularSignalStrengthDbm; + } + + /** + * Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid, + * CDMA: Ecio, EVDO: SNR, GSM: invalid + */ + public int getCellularSignalStrengthDb() { + return mCellularSignalStrengthDb; + } + + /** Whether the primary registered cell of current entry is same as that of previous entry */ + public boolean getIsSameRegisteredCell() { + return mIsSameRegisteredCell; + } } diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java index 8e371134fbd6..cd60f029dcce 100644 --- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java +++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java @@ -74,7 +74,8 @@ public class WifiUsabilityStatsEntryTest { private static WifiUsabilityStatsEntry createResult() { return new WifiUsabilityStatsEntry( - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, true ); } @@ -111,5 +112,10 @@ public class WifiUsabilityStatsEntryTest { assertEquals(expected.getProbeMcsRateSinceLastUpdate(), actual.getProbeMcsRateSinceLastUpdate()); assertEquals(expected.getRxLinkSpeedMbps(), actual.getRxLinkSpeedMbps()); + assertEquals(expected.getCellularDataNetworkType(), actual.getCellularDataNetworkType()); + assertEquals(expected.getCellularSignalStrengthDbm(), + actual.getCellularSignalStrengthDbm()); + assertEquals(expected.getCellularSignalStrengthDb(), actual.getCellularSignalStrengthDb()); + assertEquals(expected.getIsSameRegisteredCell(), actual.getIsSameRegisteredCell()); } } |