diff options
61 files changed, 953 insertions, 952 deletions
diff --git a/api/current.txt b/api/current.txt index 4a1fccf0b5ae..2f4f2c35acc2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14249,7 +14249,9 @@ package android.graphics { public class LinearGradient extends android.graphics.Shader { ctor public LinearGradient(float, float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode); + ctor public LinearGradient(float, float, float, float, @NonNull @ColorLong long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode); ctor public LinearGradient(float, float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode); + ctor public LinearGradient(float, float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode); } public class MaskFilter { @@ -14778,7 +14780,9 @@ package android.graphics { public class RadialGradient extends android.graphics.Shader { ctor public RadialGradient(float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode); + ctor public RadialGradient(float, float, float, @NonNull @ColorLong long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode); ctor public RadialGradient(float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode); + ctor public RadialGradient(float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode); } public final class RecordingCanvas extends android.graphics.Canvas { @@ -15038,7 +15042,9 @@ package android.graphics { public class SweepGradient extends android.graphics.Shader { ctor public SweepGradient(float, float, @NonNull @ColorInt int[], @Nullable float[]); + ctor public SweepGradient(float, float, @NonNull @ColorLong long[], @Nullable float[]); ctor public SweepGradient(float, float, @ColorInt int, @ColorInt int); + ctor public SweepGradient(float, float, @ColorLong long, @ColorLong long); } public class Typeface { @@ -27386,7 +27392,6 @@ package android.media.session { method public int getRatingType(); method @Nullable public android.app.PendingIntent getSessionActivity(); method @NonNull public android.media.session.MediaSession.Token getSessionToken(); - method public String getTag(); method @NonNull public android.media.session.MediaController.TransportControls getTransportControls(); method public void registerCallback(@NonNull android.media.session.MediaController.Callback); method public void registerCallback(@NonNull android.media.session.MediaController.Callback, @Nullable android.os.Handler); @@ -29281,6 +29286,7 @@ package android.net { method public android.net.VpnService.Builder setBlocking(boolean); method public android.net.VpnService.Builder setConfigureIntent(android.app.PendingIntent); method public android.net.VpnService.Builder setHttpProxy(android.net.ProxyInfo); + method public android.net.VpnService.Builder setMetered(boolean); method public android.net.VpnService.Builder setMtu(int); method public android.net.VpnService.Builder setSession(String); method public android.net.VpnService.Builder setUnderlyingNetworks(android.net.Network[]); diff --git a/api/system-current.txt b/api/system-current.txt index b22d55a46ead..d0ab334ca3f3 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -122,6 +122,7 @@ package android { field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS"; field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG"; field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT"; + field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD"; field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS"; field public static final String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING"; field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION"; @@ -3580,140 +3581,10 @@ package android.media.audiopolicy { package android.media.session { - public final class ControllerCallbackLink implements android.os.Parcelable { - ctor public ControllerCallbackLink(@NonNull android.content.Context, @NonNull android.media.session.ControllerCallbackLink.CallbackStub); - ctor public ControllerCallbackLink(android.os.IBinder); - method public int describeContents(); - method @NonNull public android.os.IBinder getBinder(); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyEvent(@NonNull String, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyExtrasChanged(@Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMetadataChanged(@Nullable android.media.MediaMetadata); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlaybackStateChanged(@Nullable android.media.session.PlaybackState); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueChanged(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueTitleChanged(@Nullable CharSequence); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySessionDestroyed(); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyVolumeInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.media.session.ControllerCallbackLink> CREATOR; - } - - public abstract static class ControllerCallbackLink.CallbackStub { - ctor public ControllerCallbackLink.CallbackStub(); - method public void onEvent(@NonNull String, @Nullable android.os.Bundle); - method public void onExtrasChanged(@Nullable android.os.Bundle); - method public void onMetadataChanged(@Nullable android.media.MediaMetadata); - method public void onPlaybackStateChanged(@Nullable android.media.session.PlaybackState); - method public void onQueueChanged(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>); - method public void onQueueTitleChanged(@Nullable CharSequence); - method public void onSessionDestroyed(); - method public void onVolumeInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo); - } - - public final class ControllerLink implements android.os.Parcelable { - ctor public ControllerLink(@NonNull android.media.session.ControllerLink.ControllerStub); - ctor public ControllerLink(android.os.IBinder); - method public int describeContents(); - method @NonNull public android.os.IBinder getBinder(); - method @Nullable public android.os.Bundle getExtras(); - method @Nullable public android.media.MediaMetadata getMetadata(); - method @Nullable public android.media.session.PlaybackState getPlaybackState(); - method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue(); - method @Nullable public CharSequence getQueueTitle(); - method public int getRatingType(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.media.session.ControllerLink> CREATOR; - } - - public abstract static class ControllerLink.ControllerStub { - ctor public ControllerLink.ControllerStub(); - method public void adjustVolume(@NonNull String, @NonNull String, @NonNull android.media.session.ControllerCallbackLink, int, int); - method public void fastForward(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method @Nullable public android.os.Bundle getExtras(); - method public long getFlags(); - method @Nullable public android.app.PendingIntent getLaunchPendingIntent(); - method @Nullable public android.media.MediaMetadata getMetadata(); - method @NonNull public String getPackageName(); - method @Nullable public android.media.session.PlaybackState getPlaybackState(); - method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue(); - method @Nullable public CharSequence getQueueTitle(); - method public int getRatingType(); - method @NonNull public String getTag(); - method @NonNull public android.media.session.MediaController.PlaybackInfo getVolumeAttributes(); - method public void next(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void pause(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void play(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void playFromMediaId(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void playFromSearch(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void playFromUri(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); - method public void prepare(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void prepareFromMediaId(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void prepareFromSearch(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void prepareFromUri(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); - method public void previous(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void rate(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.media.Rating); - method public void registerCallback(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void rewind(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void seekTo(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, long); - method public void sendCommand(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver); - method public void sendCustomAction(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public boolean sendMediaButton(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.view.KeyEvent); - method public void setVolumeTo(@NonNull String, @NonNull String, @NonNull android.media.session.ControllerCallbackLink, int, int); - method public void skipToQueueItem(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, long); - method public void stop(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); - method public void unregisterCallback(@NonNull android.media.session.ControllerCallbackLink); - } - public static final class MediaController.PlaybackInfo implements android.os.Parcelable { ctor public MediaController.PlaybackInfo(int, int, int, int, android.media.AudioAttributes); } - public abstract static class MediaSession.Callback { - method public void onSetMediaButtonEventDelegate(@NonNull android.media.session.MediaSessionEngine.MediaButtonEventDelegate); - } - - public static final class MediaSession.Token implements android.os.Parcelable { - method public android.media.session.ControllerLink getControllerLink(); - } - - public final class MediaSessionEngine implements java.lang.AutoCloseable { - ctor public MediaSessionEngine(@NonNull android.content.Context, @NonNull android.media.session.SessionLink, @NonNull android.media.session.SessionCallbackLink); - method public void close(); - method public String getCallingPackage(); - method @NonNull public android.media.session.MediaController getController(); - method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo(); - method @NonNull public android.media.session.MediaSession.Token getSessionToken(); - method public boolean isActive(); - method public static boolean isActiveState(int); - method public void sendSessionEvent(@NonNull String, @Nullable android.os.Bundle); - method public void setActive(boolean); - method public void setCallback(@Nullable android.media.session.MediaSession.Callback); - method public void setCallback(@Nullable android.media.session.MediaSession.Callback, @NonNull android.os.Handler); - method public void setExtras(@Nullable android.os.Bundle); - method public void setFlags(int); - method public void setMediaButtonReceiver(@Nullable android.app.PendingIntent); - method public void setMetadata(@Nullable android.media.MediaMetadata); - method public void setPlaybackState(@Nullable android.media.session.PlaybackState); - method public void setPlaybackToLocal(android.media.AudioAttributes); - method public void setPlaybackToRemote(@NonNull android.media.VolumeProvider); - method public void setQueue(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>); - method public void setQueueTitle(@Nullable CharSequence); - method public void setRatingType(int); - method public void setSessionActivity(@Nullable android.app.PendingIntent); - } - - public static interface MediaSessionEngine.MediaButtonEventDelegate { - method public boolean onMediaButtonIntent(android.content.Intent); - } - - public static final class MediaSessionEngine.QueueItem { - ctor public MediaSessionEngine.QueueItem(android.media.MediaDescription, long); - ctor public MediaSessionEngine.QueueItem(android.os.Parcel); - method public android.media.MediaDescription getDescription(); - method public long getQueueId(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int UNKNOWN_ID = -1; // 0xffffffff - } - public final class MediaSessionManager { method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler); @@ -3727,66 +3598,6 @@ package android.media.session { method public void onVolumeKeyLongPress(android.view.KeyEvent); } - public final class SessionCallbackLink implements android.os.Parcelable { - ctor public SessionCallbackLink(android.os.IBinder); - method public int describeContents(); - method @NonNull public android.os.IBinder getBinder(); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyAdjustVolume(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCommand(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCustomAction(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyFastForward(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButton(@NonNull String, int, int, @NonNull android.content.Intent, int, @Nullable android.os.ResultReceiver); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButtonFromController(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.content.Intent); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyNext(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPause(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlay(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepare(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrevious(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRate(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.media.Rating); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRewind(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySeekTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySetVolumeTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySkipToTrack(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long); - method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyStop(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.media.session.SessionCallbackLink> CREATOR; - } - - public final class SessionLink implements android.os.Parcelable { - ctor public SessionLink(@NonNull android.media.session.SessionLink.SessionStub); - ctor public SessionLink(android.os.IBinder); - method public int describeContents(); - method @NonNull public android.os.IBinder getBinder(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.media.session.SessionLink> CREATOR; - } - - public abstract static class SessionLink.SessionStub { - ctor public SessionLink.SessionStub(); - method public void destroySession(); - method @NonNull public android.media.session.ControllerLink getController(); - method public void sendEvent(@NonNull String, @Nullable android.os.Bundle); - method public void setActive(boolean); - method public void setCurrentVolume(int); - method public void setExtras(@Nullable android.os.Bundle); - method public void setFlags(int); - method public void setLaunchPendingIntent(@Nullable android.app.PendingIntent); - method public void setMediaButtonReceiver(@Nullable android.app.PendingIntent); - method public void setMetadata(@Nullable android.media.MediaMetadata, long, @Nullable String); - method public void setPlaybackState(@Nullable android.media.session.PlaybackState); - method public void setPlaybackToLocal(@NonNull android.media.AudioAttributes); - method public void setPlaybackToRemote(int, int); - method public void setQueue(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>); - method public void setQueueTitle(@Nullable CharSequence); - method public void setRatingType(int); - } - } package android.media.soundtrigger { @@ -4088,7 +3899,7 @@ package android.net { } public class ConnectivityManager { - method @RequiresPermission("android.permission.PACKET_KEEPALIVE_OFFLOAD") public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); + method @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); method public boolean getAvoidBadWifi(); method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl(); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); @@ -7907,6 +7718,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getLogicalToPhysicalSlotMapping(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmap(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState(); method public int getSimApplicationState(); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 6f01d7cdd073..427662aa9eaa 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -234,6 +234,7 @@ message Atom { BluetoothBondStateChanged bluetooth_bond_state_changed = 165; BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166; BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167; + ScreenTimeoutExtensionReported screen_timeout_extension_reported = 168; } // Pulled events will start at field 10000. @@ -4983,17 +4984,17 @@ message GnssConfigurationReported { * packages/apps/Nfc/src/com/android/nfc/cardemulation/AidRoutingManager.java */ message NfcErrorOccurred { - enum Type { - UNKNOWN = 0; - CMD_TIMEOUT = 1; - ERROR_NOTIFICATION = 2; - AID_OVERFLOW = 3; - } - optional Type type = 1; - // If it's nci cmd timeout, log the timeout command. - optional uint32 nci_cmd = 2; + enum Type { + UNKNOWN = 0; + CMD_TIMEOUT = 1; + ERROR_NOTIFICATION = 2; + AID_OVERFLOW = 3; + } + optional Type type = 1; + // If it's nci cmd timeout, log the timeout command. + optional uint32 nci_cmd = 2; - optional uint32 error_ntf_status_code = 3; + optional uint32 error_ntf_status_code = 3; } /** @@ -5002,14 +5003,14 @@ message NfcErrorOccurred { * packages/apps/Nfc/src/com/android/nfc/NfcService.java */ message NfcStateChanged { - enum State { - UNKNOWN = 0; - OFF = 1; - ON = 2; - ON_LOCKED = 3; // Secure Nfc enabled. - CRASH_RESTART = 4; // NfcService watchdog timeout restart. - } - optional State state = 1; + enum State { + UNKNOWN = 0; + OFF = 1; + ON = 2; + ON_LOCKED = 3; // Secure Nfc enabled. + CRASH_RESTART = 4; // NfcService watchdog timeout restart. + } + optional State state = 1; } /** @@ -5018,12 +5019,12 @@ message NfcStateChanged { * packages/apps/Nfc/src/com/android/nfc/P2pLinkManager.java */ message NfcBeamOccurred { - enum Operation { - UNKNOWN = 0; - SEND = 1; - RECEIVE = 2; - } - optional Operation operation = 1; + enum Operation { + UNKNOWN = 0; + SEND = 1; + RECEIVE = 2; + } + optional Operation operation = 1; } /** @@ -5033,16 +5034,16 @@ message NfcBeamOccurred { * packages/apps/Nfc/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java */ message NfcCardemulationOccurred { - enum Category { - UNKNOWN = 0; - HCE_PAYMENT = 1; - HCE_OTHER = 2; - OFFHOST = 3; - } - // Transaction belongs to HCE payment or HCE other category, or offhost. - optional Category category = 1; - // SeName from transaction: SIMx, eSEx, HCE, HCEF. - optional string se_name = 2; + enum Category { + UNKNOWN = 0; + HCE_PAYMENT = 1; + HCE_OTHER = 2; + OFFHOST = 3; + } + // Transaction belongs to HCE payment or HCE other category, or offhost. + optional Category category = 1; + // SeName from transaction: SIMx, eSEx, HCE, HCEF. + optional string se_name = 2; } /** @@ -5051,16 +5052,16 @@ message NfcCardemulationOccurred { * packages/apps/Nfc/src/com/android/nfc/NfcDispatcher.java */ message NfcTagOccurred { - enum Type { - UNKNOWN = 0; - URL = 1; - BT_PAIRING = 2; - PROVISION = 3; - WIFI_CONNECT = 4; - APP_LAUNCH = 5; - OTHERS = 6; - } - optional Type type = 1; + enum Type { + UNKNOWN = 0; + URL = 1; + BT_PAIRING = 2; + PROVISION = 3; + WIFI_CONNECT = 4; + APP_LAUNCH = 5; + OTHERS = 6; + } + optional Type type = 1; } /** @@ -5080,18 +5081,18 @@ message NfcHceTransactionOccurred { * packages/apps/SecureElement/src/com/android/se/Terminal.java */ message SeStateChanged { - enum State { - UNKNOWN = 0; - INITIALIZED = 1; - DISCONNECTED = 2; - CONNECTED = 3; - HALCRASH = 4; - } - optional State state = 1; + enum State { + UNKNOWN = 0; + INITIALIZED = 1; + DISCONNECTED = 2; + CONNECTED = 3; + HALCRASH = 4; + } + optional State state = 1; - optional string state_change_reason = 2; - // SIMx or eSEx. - optional string terminal = 3; + optional string state_change_reason = 2; + // SIMx or eSEx. + optional string terminal = 3; } /** @@ -5100,15 +5101,15 @@ message SeStateChanged { * packages/apps/SecureElement/src/com/android/se/Terminal.java */ message SeOmapiReported { - enum Operation { - UNKNOWN = 0; - OPEN_CHANNEL = 1; - } - optional Operation operation = 1; - // SIMx or eSEx. - optional string terminal = 2; + enum Operation { + UNKNOWN = 0; + OPEN_CHANNEL = 1; + } + optional Operation operation = 1; + // SIMx or eSEx. + optional string terminal = 2; - optional string package_name = 3; + optional string package_name = 3; } /** @@ -5290,3 +5291,15 @@ message ScheduledJobConstraintChanged { } optional State state = 4; } + +/** + * Logs PowerManagerService screen timeout resets (extensions) that happen when an attention check + * returns true. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java + */ +message ScreenTimeoutExtensionReported { + // Describes how many times in a row did the power manager reset the screen off timeout. + optional uint32 consecutive_timeout_extended_count = 1; +} diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 03a09ee04ea1..4a8566c0072c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -6083,7 +6083,12 @@ public final class ActivityThread extends ClientTransactionHandler { instrApp.initForUser(UserHandle.myUserId()); final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, appContext.getClassLoader(), false, true, false); - final ContextImpl instrContext = ContextImpl.createAppContext(this, pi); + + // The test context's op package name == the target app's op package name, because + // the app ops manager checks the op package name against the real calling UID, + // which is what the target package name is associated with. + final ContextImpl instrContext = ContextImpl.createAppContext(this, pi, + appContext.getOpPackageName()); try { final ClassLoader cl = instrContext.getClassLoader(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 92cdb20c7f4f..1a728c12e138 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2128,7 +2128,7 @@ class ContextImpl extends Context { flags | CONTEXT_REGISTER_PACKAGE); if (pi != null) { ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, - new UserHandle(UserHandle.getUserId(application.uid)), flags, null); + new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null); final int displayId = getDisplayId(); @@ -2156,14 +2156,14 @@ class ContextImpl extends Context { // The system resources are loaded in every application, so we can safely copy // the context without reloading Resources. return new ContextImpl(this, mMainThread, mPackageInfo, null, mActivityToken, user, - flags, null); + flags, null, null); } LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); if (pi != null) { ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user, - flags, null); + flags, null, null); final int displayId = getDisplayId(); @@ -2190,7 +2190,7 @@ class ContextImpl extends Context { final String[] paths = mPackageInfo.getSplitPaths(splitName); final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, splitName, - mActivityToken, mUser, mFlags, classLoader); + mActivityToken, mUser, mFlags, classLoader, null); final int displayId = getDisplayId(); @@ -2214,7 +2214,7 @@ class ContextImpl extends Context { } ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, - mActivityToken, mUser, mFlags, mClassLoader); + mActivityToken, mUser, mFlags, mClassLoader, null); final int displayId = getDisplayId(); context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, @@ -2229,7 +2229,7 @@ class ContextImpl extends Context { } ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, - mActivityToken, mUser, mFlags, mClassLoader); + mActivityToken, mUser, mFlags, mClassLoader, null); final int displayId = display.getDisplayId(); context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, @@ -2243,7 +2243,7 @@ class ContextImpl extends Context { final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) | Context.CONTEXT_DEVICE_PROTECTED_STORAGE; return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, - flags, mClassLoader); + flags, mClassLoader, null); } @Override @@ -2251,7 +2251,7 @@ class ContextImpl extends Context { final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE) | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, - flags, mClassLoader); + flags, mClassLoader, null); } @Override @@ -2397,7 +2397,7 @@ class ContextImpl extends Context { static ContextImpl createSystemContext(ActivityThread mainThread) { LoadedApk packageInfo = new LoadedApk(mainThread); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, - null); + null, null); context.setResources(packageInfo.getResources()); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), context.mResourcesManager.getDisplayMetrics()); @@ -2414,7 +2414,7 @@ class ContextImpl extends Context { static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) { final LoadedApk packageInfo = systemContext.mPackageInfo; ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null, - null, null, 0, null); + null, null, 0, null, null); context.setResources(createResources(null, packageInfo, null, displayId, null, packageInfo.getCompatibilityInfo())); context.updateDisplay(displayId); @@ -2431,9 +2431,14 @@ class ContextImpl extends Context { @UnsupportedAppUsage static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { + return createAppContext(mainThread, packageInfo, null); + } + + static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo, + String opPackageName) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, - null); + null, opPackageName); context.setResources(packageInfo.getResources()); return context; } @@ -2461,7 +2466,7 @@ class ContextImpl extends Context { } ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName, - activityToken, null, 0, classLoader); + activityToken, null, 0, classLoader, null); // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY. displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY; @@ -2491,7 +2496,7 @@ class ContextImpl extends Context { private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, @NonNull LoadedApk packageInfo, @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, - @Nullable ClassLoader classLoader) { + @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) { mOuterContext = this; // If creator didn't specify which storage to use, use the default @@ -2520,9 +2525,11 @@ class ContextImpl extends Context { mClassLoader = classLoader; mResourcesManager = ResourcesManager.getInstance(); + String opPackageName; + if (container != null) { mBasePackageName = container.mBasePackageName; - mOpPackageName = container.mOpPackageName; + opPackageName = container.mOpPackageName; setResources(container.mResources); mDisplay = container.mDisplay; } else { @@ -2533,12 +2540,14 @@ class ContextImpl extends Context { // processes. For purposes of app ops, we must then consider the context as // belonging to the package of this process, not the system itself, otherwise // the package+uid verifications in app ops will fail. - mOpPackageName = ActivityThread.currentPackageName(); + opPackageName = ActivityThread.currentPackageName(); } else { - mOpPackageName = mBasePackageName; + opPackageName = mBasePackageName; } } + mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName; + mContentResolver = new ApplicationContentResolver(this, mainThread); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 7c550d4332fe..028e3efc9fb8 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -8122,6 +8122,10 @@ public class Notification implements Parcelable big.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE); } } + bindMediaActionButton(big, R.id.media_seamless, new Action(R.drawable.ic_media_seamless, + mBuilder.mContext.getString( + com.android.internal.R.string.ext_media_seamless_action), null), p); + big.setViewVisibility(R.id.media_seamless, View.GONE); handleImage(big); return big; } diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index dc099a46aa2a..784f23311103 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -791,6 +791,27 @@ public class VpnService extends Service { } /** + * Marks the VPN network as metered. A VPN network is classified as metered when the user is + * sensitive to heavy data usage due to monetary costs and/or data limitations. In such + * cases, you should set this to {@code true} so that apps on the system can avoid doing + * large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN + * network to inherit its meteredness from its underlying networks. + * + * <p>VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be + * considered metered by default. + * + * @param isMetered {@code true} if VPN network should be treated as metered regardless of + * underlying network meteredness + * @return this {@link Builder} object to facilitate chaining method calls + * @see #setUnderlyingNetworks(Networks[]) + * @see ConnectivityManager#isActiveNetworkMetered() + */ + public Builder setMetered(boolean isMetered) { + mConfig.isMetered = isMetered; + return this; + } + + /** * Create a VPN interface using the parameters supplied to this * builder. The interface works on IP packets, and a file descriptor * is returned for the application to access them. Each read diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index afa21100f022..dcda8a305f14 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7467,14 +7467,6 @@ public final class Settings { private static final Validator DOZE_TAP_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR; /** - * Gesture that wakes up the lock screen. - * @hide - */ - public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_lock_screen_gesture"; - - private static final Validator DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR; - - /** * Gesture that wakes up the display, showing the ambient version of the status bar. * @hide */ @@ -8589,7 +8581,6 @@ public final class Settings { DOZE_PICK_UP_GESTURE, DOZE_DOUBLE_TAP_GESTURE, DOZE_TAP_SCREEN_GESTURE, - DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE, NFC_PAYMENT_DEFAULT_COMPONENT, AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, @@ -8749,7 +8740,6 @@ public final class Settings { VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR); VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR); VALIDATORS.put(DOZE_TAP_SCREEN_GESTURE, DOZE_TAP_SCREEN_GESTURE_VALIDATOR); - VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR); VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR); VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR); VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 2e8b7f021ff6..1ca6398e3bc0 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -36,6 +36,7 @@ public class FeatureFlagUtils { public static final String FFLAG_PREFIX = "sys.fflag."; public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override."; public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX; + public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer"; public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; public static final String SAFETY_HUB = "settings_safety_hub"; public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press"; @@ -51,13 +52,13 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_dynamic_homepage", "true"); DEFAULT_FLAGS.put("settings_mobile_network_v2", "true"); DEFAULT_FLAGS.put("settings_network_and_internet_v2", "false"); - DEFAULT_FLAGS.put("settings_seamless_transfer", "false"); DEFAULT_FLAGS.put("settings_slice_injection", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put("settings_wifi_dpp", "true"); DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true"); DEFAULT_FLAGS.put("settings_wifi_sharing", "true"); DEFAULT_FLAGS.put("settings_mainline_module", "false"); + DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false"); DEFAULT_FLAGS.put(SAFETY_HUB, "false"); DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false"); diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java index 7a00a51647f6..e19a32e72a98 100644 --- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java +++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java @@ -38,7 +38,7 @@ public class AmbientDisplayConfiguration { return pulseOnNotificationEnabled(user) || pulseOnLongPressEnabled(user) || alwaysOnEnabled(user) - || wakeLockScreenGestureEnabled(user); + || wakeScreenGestureEnabled(user); } public boolean pulseOnNotificationEnabled(int user) { @@ -76,11 +76,6 @@ public class AmbientDisplayConfiguration { return !TextUtils.isEmpty(doubleTapSensorType()); } - public boolean wakeLockScreenGestureEnabled(int user) { - return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user) - && wakeScreenGestureAvailable(); - } - public boolean wakeScreenGestureAvailable() { return mContext.getResources() .getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable); diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index da8605e645b4..65b974ba8b42 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -104,6 +104,7 @@ public class VpnConfig implements Parcelable { public boolean allowBypass; public boolean allowIPv4; public boolean allowIPv6; + public boolean isMetered = true; public Network[] underlyingNetworks; public ProxyInfo proxyInfo; @@ -165,6 +166,7 @@ public class VpnConfig implements Parcelable { out.writeInt(allowBypass ? 1 : 0); out.writeInt(allowIPv4 ? 1 : 0); out.writeInt(allowIPv6 ? 1 : 0); + out.writeInt(isMetered ? 1 : 0); out.writeTypedArray(underlyingNetworks, flags); out.writeParcelable(proxyInfo, flags); } @@ -191,6 +193,7 @@ public class VpnConfig implements Parcelable { config.allowBypass = in.readInt() != 0; config.allowIPv4 = in.readInt() != 0; config.allowIPv6 = in.readInt() != 0; + config.isMetered = in.readInt() != 0; config.underlyingNetworks = in.createTypedArray(Network.CREATOR); config.proxyInfo = in.readParcelable(null); return config; diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index ed6a84b35670..e7419796bd5d 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -8,6 +8,8 @@ #include <jni.h> +#include <vector> + using namespace android::uirenderer; /** @@ -18,11 +20,11 @@ using namespace android::uirenderer; */ static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag; -static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { - if (NULL == ptr) { - doThrowIAE(env); +#define ThrowIAE_IfNull(env, ptr) \ + if (nullptr == ptr) { \ + doThrowIAE(env); \ + return 0; \ } -} static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray) { @@ -76,186 +78,115 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j } sk_sp<SkShader> shader = image->makeShader( (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY); + ThrowIAE_IfNull(env, shader.get()); if (matrix) { shader = shader->makeWithLocalMatrix(*matrix); } - ThrowIAE_IfNull(env, shader.get()); return reinterpret_cast<jlong>(shader.release()); } /////////////////////////////////////////////////////////////////////////////////////////////// -static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr, - jfloat x0, jfloat y0, jfloat x1, jfloat y1, - jintArray colorArray, jfloatArray posArray, jint tileMode) { - const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); +static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) { + const size_t count = env->GetArrayLength(colorArray); + const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr); + + std::vector<SkColor4f> colors(count); + for (size_t i = 0; i < count; ++i) { + colors[i] = GraphicsJNI::convertColorLong(colorValues[i]); + } + + env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT); + return colors; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr, + jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray, + jfloatArray posArray, jint tileMode, long colorSpaceHandle) { SkPoint pts[2]; pts[0].set(x0, y0); pts[1].set(x1, y1); - size_t count = env->GetArrayLength(colorArray); - const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); + std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); - AutoJavaFloatArray autoPos(env, posArray, count); + AutoJavaFloatArray autoPos(env, posArray, colors.size()); #ifdef SK_SCALAR_IS_FLOAT SkScalar* pos = autoPos.ptr(); #else #error Need to convert float array to SkScalar array before calling the following function. #endif - sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, - reinterpret_cast<const SkColor*>(colorValues), pos, count, - static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL)); - - SkShader* shader; - if (matrix) { - shader = baseShader->makeWithLocalMatrix(*matrix).release(); - } else { - shader = baseShader.release(); - } - - env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); + sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0], + GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), + static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr)); ThrowIAE_IfNull(env, shader); - return reinterpret_cast<jlong>(shader); -} -static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr, - jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) { const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); - - SkPoint pts[2]; - pts[0].set(x0, y0); - pts[1].set(x1, y1); - - SkColor colors[2]; - colors[0] = color0; - colors[1] = color1; - - sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, colors, NULL, 2, - static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL)); - - SkShader* s; if (matrix) { - s = baseShader->makeWithLocalMatrix(*matrix).release(); - } else { - s = baseShader.release(); + shader = shader->makeWithLocalMatrix(*matrix); } - ThrowIAE_IfNull(env, s); - return reinterpret_cast<jlong>(s); + return reinterpret_cast<jlong>(shader.release()); } /////////////////////////////////////////////////////////////////////////////////////////////// -static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, - jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) { - const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); +static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, + jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode, + jlong colorSpaceHandle) { SkPoint center; center.set(x, y); - size_t count = env->GetArrayLength(colorArray); - const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); + std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); - AutoJavaFloatArray autoPos(env, posArray, count); + AutoJavaFloatArray autoPos(env, posArray, colors.size()); #ifdef SK_SCALAR_IS_FLOAT SkScalar* pos = autoPos.ptr(); #else #error Need to convert float array to SkScalar array before calling the following function. #endif - sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, - reinterpret_cast<const SkColor*>(colorValues), pos, count, - static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL); - - SkShader* shader; - if (matrix) { - shader = baseShader->makeWithLocalMatrix(*matrix).release(); - } else { - shader = baseShader.release(); - } - - env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), - JNI_ABORT); - + sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0], + GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), + static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr); ThrowIAE_IfNull(env, shader); - return reinterpret_cast<jlong>(shader); -} -static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius, - jint color0, jint color1, jint tileMode) { const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); - SkPoint center; - center.set(x, y); - - SkColor colors[2]; - colors[0] = color0; - colors[1] = color1; - - sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2, - static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL); - - SkShader* shader; if (matrix) { - shader = baseShader->makeWithLocalMatrix(*matrix).release(); - } else { - shader = baseShader.release(); + shader = shader->makeWithLocalMatrix(*matrix); } - ThrowIAE_IfNull(env, shader); - return reinterpret_cast<jlong>(shader); + + return reinterpret_cast<jlong>(shader.release()); } /////////////////////////////////////////////////////////////////////////////// -static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, - jintArray jcolors, jfloatArray jpositions) { - const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); - size_t count = env->GetArrayLength(jcolors); - const jint* colors = env->GetIntArrayElements(jcolors, NULL); +static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, + jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) { + std::vector<SkColor4f> colors = convertColorLongs(env, colorArray); - AutoJavaFloatArray autoPos(env, jpositions, count); + AutoJavaFloatArray autoPos(env, jpositions, colors.size()); #ifdef SK_SCALAR_IS_FLOAT SkScalar* pos = autoPos.ptr(); #else #error Need to convert float array to SkScalar array before calling the following function. #endif - sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, - reinterpret_cast<const SkColor*>(colors), pos, count, - sGradientShaderFlags, NULL); - - SkShader* shader; - if (matrix) { - shader = baseShader->makeWithLocalMatrix(*matrix).release(); - } else { - shader = baseShader.release(); - } - - env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors), - JNI_ABORT); + sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0], + GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(), + sGradientShaderFlags, nullptr); ThrowIAE_IfNull(env, shader); - return reinterpret_cast<jlong>(shader); -} -static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, - int color0, int color1) { const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); - SkColor colors[2]; - colors[0] = color0; - colors[1] = color1; - - sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, colors, - NULL, 2, sGradientShaderFlags, NULL); - - SkShader* shader; if (matrix) { - shader = baseShader->makeWithLocalMatrix(*matrix).release(); - } else { - shader = baseShader.release(); + shader = shader->makeWithLocalMatrix(*matrix); } - ThrowIAE_IfNull(env, shader); - return reinterpret_cast<jlong>(shader); + + return reinterpret_cast<jlong>(shader.release()); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -295,18 +226,15 @@ static const JNINativeMethod gBitmapShaderMethods[] = { }; static const JNINativeMethod gLinearGradientMethods[] = { - { "nativeCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_create1 }, - { "nativeCreate2", "(JFFFFIII)J", (void*)LinearGradient_create2 }, + { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create }, }; static const JNINativeMethod gRadialGradientMethods[] = { - { "nativeCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_create1 }, - { "nativeCreate2", "(JFFFIII)J", (void*)RadialGradient_create2 }, + { "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create }, }; static const JNINativeMethod gSweepGradientMethods[] = { - { "nativeCreate1", "(JFF[I[F)J", (void*)SweepGradient_create1 }, - { "nativeCreate2", "(JFFII)J", (void*)SweepGradient_create2 }, + { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create }, }; static const JNINativeMethod gComposeShaderMethods[] = { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index b4afc71b2c5d..bc9dc575d306 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1730,7 +1730,7 @@ <permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" android:protectionLevel="signature|privileged" /> - <!-- Allows a system application to access hardware packet offload capabilities. + <!-- @SystemApi Allows a system application to access hardware packet offload capabilities. @hide --> <permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" android:protectionLevel="signature|privileged" /> diff --git a/core/res/res/drawable/ic_media_seamless.xml b/core/res/res/drawable/ic_media_seamless.xml new file mode 100644 index 000000000000..122e9c586095 --- /dev/null +++ b/core/res/res/drawable/ic_media_seamless.xml @@ -0,0 +1,25 @@ +<!-- + Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="#FF000000" + android:pathData="M12,3l0.01,10.55c-0.59,-0.34 -1.27,-0.55 -2,-0.55C7.79,13 6,14.79 6,17c0,2.21 1.79,4 4.01,4S14,19.21 14,17V7h4V3H12zM10.01,19c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C12.01,18.1 11.11,19 10.01,19z"/> +</vector> diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml index 5cb93eb9319a..56f7a593cc43 100644 --- a/core/res/res/layout/notification_template_material_big_media.xml +++ b/core/res/res/layout/notification_template_material_big_media.xml @@ -79,6 +79,10 @@ layout="@layout/notification_material_media_action" android:id="@+id/action4" /> + <include + layout="@layout/notification_material_media_action" + android:id="@+id/media_seamless" + /> </LinearLayout> </LinearLayout> </com.android.internal.widget.MediaNotificationView> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index ef3834cccc15..baf758752abe 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -240,7 +240,7 @@ <dimen name="notification_header_icon_size">18dp</dimen> <!-- size (width and height) of the icon in the notification header --> - <dimen name="notification_header_icon_size_ambient">20dp</dimen> + <dimen name="notification_header_icon_size_ambient">18dp</dimen> <!-- The margin before the start of the app name in the header. --> <dimen name="notification_header_app_name_margin_start">3dp</dimen> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 6adb4a711857..04df97c455a8 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3692,6 +3692,9 @@ <!-- Notification action to browse external media [CHAR LIMIT=20] --> <string name="ext_media_browse_action">Explore</string> + <!-- Notification action to transfer media [CHAR LIMIT=40] --> + <string name="ext_media_seamless_action">Seamless transfer</string> + <!-- Notification title when external media is missing [CHAR LIMIT=30] --> <string name="ext_media_missing_title"><xliff:g id="name" example="SD card">%s</xliff:g> missing</string> <!-- Notification body when external media is missing [CHAR LIMIT=30] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 5400d94ed033..52400de3fe2b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -191,6 +191,7 @@ <java-symbol type="id" name="action2" /> <java-symbol type="id" name="action3" /> <java-symbol type="id" name="action4" /> + <java-symbol type="id" name="media_seamless" /> <java-symbol type="id" name="big_picture" /> <java-symbol type="id" name="big_text" /> <java-symbol type="id" name="chronometer" /> @@ -2237,6 +2238,7 @@ <java-symbol type="string" name="ext_media_init_action" /> <java-symbol type="string" name="ext_media_unmount_action" /> <java-symbol type="string" name="ext_media_browse_action" /> + <java-symbol type="string" name="ext_media_seamless_action" /> <java-symbol type="string" name="ext_media_missing_title" /> <java-symbol type="string" name="ext_media_missing_message" /> <java-symbol type="string" name="ext_media_move_specific_title" /> @@ -3098,6 +3100,7 @@ <java-symbol type="drawable" name="ic_restart" /> <java-symbol type="drawable" name="ic_screenshot" /> <java-symbol type="drawable" name="ic_faster_emergency" /> + <java-symbol type="drawable" name="ic_media_seamless" /> <java-symbol type="drawable" name="emergency_icon" /> <java-symbol type="array" name="config_convert_to_emergency_number_map" /> diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java index 7e6fc353cf1e..ad33f797877c 100644 --- a/graphics/java/android/graphics/LinearGradient.java +++ b/graphics/java/android/graphics/LinearGradient.java @@ -17,21 +17,13 @@ package android.graphics; import android.annotation.ColorInt; +import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; -public class LinearGradient extends Shader { - - private static final int TYPE_COLORS_AND_POSITIONS = 1; - private static final int TYPE_COLOR_START_AND_COLOR_END = 2; - - /** - * Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or - * TYPE_COLOR_START_AND_COLOR_END. - */ - private int mType; +public class LinearGradient extends Shader { @UnsupportedAppUsage private float mX0; @UnsupportedAppUsage @@ -41,16 +33,43 @@ public class LinearGradient extends Shader { @UnsupportedAppUsage private float mY1; @UnsupportedAppUsage - private int[] mColors; - @UnsupportedAppUsage private float[] mPositions; @UnsupportedAppUsage + private TileMode mTileMode; + + // @ColorInts are replaced by @ColorLongs, but these remain due to @UnsupportedAppUsage. + @UnsupportedAppUsage + @ColorInt + private int[] mColors; + @UnsupportedAppUsage + @ColorInt private int mColor0; @UnsupportedAppUsage + @ColorInt private int mColor1; - @UnsupportedAppUsage - private TileMode mTileMode; + @ColorLong + private final long[] mColorLongs; + + + /** + * Create a shader that draws a linear gradient along a line. + * + * @param x0 The x-coordinate for the start of the gradient line + * @param y0 The y-coordinate for the start of the gradient line + * @param x1 The x-coordinate for the end of the gradient line + * @param y1 The y-coordinate for the end of the gradient line + * @param colors The sRGB colors to be distributed along the gradient line + * @param positions May be null. The relative positions [0..1] of + * each corresponding color in the colors array. If this is null, + * the the colors are distributed evenly along the gradient line. + * @param tile The Shader tiling mode + */ + public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int[] colors, + @Nullable float[] positions, @NonNull TileMode tile) { + this(x0, y0, x1, y1, convertColors(colors), positions, tile, + ColorSpace.get(ColorSpace.Named.SRGB)); + } /** * Create a shader that draws a linear gradient along a line. @@ -64,21 +83,33 @@ public class LinearGradient extends Shader { * each corresponding color in the colors array. If this is null, * the the colors are distributed evenly along the gradient line. * @param tile The Shader tiling mode - */ - public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], - @Nullable float positions[], @NonNull TileMode tile) { - if (colors.length < 2) { - throw new IllegalArgumentException("needs >= 2 number of colors"); - } + * + * @throws IllegalArgumentException if there are less than two colors, the colors do + * not share the same {@link ColorSpace} or do not use a valid one, or {@code positions} + * is not {@code null} and has a different length from {@code colors}. + */ + public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorLong long[] colors, + @Nullable float[] positions, @NonNull TileMode tile) { + this(x0, y0, x1, y1, colors.clone(), positions, tile, detectColorSpace(colors)); + } + + /** + * Base constructor. Assumes @param colors is a copy that this object can hold onto, + * and all colors share @param colorSpace. + */ + private LinearGradient(float x0, float y0, float x1, float y1, + @NonNull @ColorLong long[] colors, @Nullable float[] positions, @NonNull TileMode tile, + @NonNull ColorSpace colorSpace) { + super(colorSpace); + if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } - mType = TYPE_COLORS_AND_POSITIONS; mX0 = x0; mY0 = y0; mX1 = x1; mY1 = y1; - mColors = colors.clone(); + mColorLongs = colors; mPositions = positions != null ? positions.clone() : null; mTileMode = tile; } @@ -90,34 +121,41 @@ public class LinearGradient extends Shader { * @param y0 The y-coordinate for the start of the gradient line * @param x1 The x-coordinate for the end of the gradient line * @param y1 The y-coordinate for the end of the gradient line + * @param color0 The sRGB color at the start of the gradient line. + * @param color1 The sRGB color at the end of the gradient line. + * @param tile The Shader tiling mode + */ + public LinearGradient(float x0, float y0, float x1, float y1, + @ColorInt int color0, @ColorInt int color1, + @NonNull TileMode tile) { + this(x0, y0, x1, y1, Color.pack(color0), Color.pack(color1), tile); + } + + /** + * Create a shader that draws a linear gradient along a line. + * + * @param x0 The x-coordinate for the start of the gradient line + * @param y0 The y-coordinate for the start of the gradient line + * @param x1 The x-coordinate for the end of the gradient line + * @param y1 The y-coordinate for the end of the gradient line * @param color0 The color at the start of the gradient line. * @param color1 The color at the end of the gradient line. * @param tile The Shader tiling mode - */ + * + * @throws IllegalArgumentException if the colors do + * not share the same {@link ColorSpace} or do not use a valid one. + */ public LinearGradient(float x0, float y0, float x1, float y1, - @ColorInt int color0, @ColorInt int color1, + @ColorLong long color0, @ColorLong long color1, @NonNull TileMode tile) { - mType = TYPE_COLOR_START_AND_COLOR_END; - mX0 = x0; - mY0 = y0; - mX1 = x1; - mY1 = y1; - mColor0 = color0; - mColor1 = color1; - mColors = null; - mPositions = null; - mTileMode = tile; + this(x0, y0, x1, y1, new long[] {color0, color1}, null, tile); } @Override long createNativeInstance(long nativeMatrix) { - if (mType == TYPE_COLORS_AND_POSITIONS) { - return nativeCreate1(nativeMatrix, mX0, mY0, mX1, mY1, - mColors, mPositions, mTileMode.nativeInt); - } else { // TYPE_COLOR_START_AND_COLOR_END - return nativeCreate2(nativeMatrix, mX0, mY0, mX1, mY1, - mColor0, mColor1, mTileMode.nativeInt); - } + return nativeCreate(nativeMatrix, mX0, mY0, mX1, mY1, + mColorLongs, mPositions, mTileMode.nativeInt, + colorSpace().getNativeInstance()); } /** @@ -125,19 +163,12 @@ public class LinearGradient extends Shader { */ @Override protected Shader copy() { - final LinearGradient copy; - if (mType == TYPE_COLORS_AND_POSITIONS) { - copy = new LinearGradient(mX0, mY0, mX1, mY1, mColors.clone(), - mPositions != null ? mPositions.clone() : null, mTileMode); - } else { // TYPE_COLOR_START_AND_COLOR_END - copy = new LinearGradient(mX0, mY0, mX1, mY1, mColor0, mColor1, mTileMode); - } + final LinearGradient copy = new LinearGradient(mX0, mY0, mX1, mY1, mColorLongs, + mPositions, mTileMode, colorSpace()); copyLocalMatrix(copy); return copy; } - private native long nativeCreate1(long matrix, float x0, float y0, float x1, float y1, - int colors[], float positions[], int tileMode); - private native long nativeCreate2(long matrix, float x0, float y0, float x1, float y1, - int color0, int color1, int tileMode); + private native long nativeCreate(long matrix, float x0, float y0, float x1, float y1, + long[] colors, float[] positions, int tileMode, long colorSpaceHandle); } diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index 41d26281b723..5e1618022169 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -16,22 +16,13 @@ package android.graphics; +import android.annotation.ColorInt; +import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.ColorInt; import android.annotation.UnsupportedAppUsage; public class RadialGradient extends Shader { - - private static final int TYPE_COLORS_AND_POSITIONS = 1; - private static final int TYPE_COLOR_CENTER_AND_COLOR_EDGE = 2; - - /** - * Type of the RadialGradient: can be either TYPE_COLORS_AND_POSITIONS or - * TYPE_COLOR_CENTER_AND_COLOR_EDGE. - */ - private int mType; - @UnsupportedAppUsage private float mX; @UnsupportedAppUsage @@ -39,16 +30,43 @@ public class RadialGradient extends Shader { @UnsupportedAppUsage private float mRadius; @UnsupportedAppUsage - private int[] mColors; - @UnsupportedAppUsage private float[] mPositions; @UnsupportedAppUsage + private TileMode mTileMode; + + // @ColorInts are replaced by @ColorLongs, but these remain due to @UnsupportedAppUsage. + @UnsupportedAppUsage + @ColorInt + private int[] mColors; + @UnsupportedAppUsage + @ColorInt private int mCenterColor; @UnsupportedAppUsage + @ColorInt private int mEdgeColor; - @UnsupportedAppUsage - private TileMode mTileMode; + @ColorLong + private final long[] mColorLongs; + + /** + * Create a shader that draws a radial gradient given the center and radius. + * + * @param centerX The x-coordinate of the center of the radius + * @param centerY The y-coordinate of the center of the radius + * @param radius Must be positive. The radius of the circle for this gradient. + * @param colors The sRGB colors to be distributed between the center and edge of the circle + * @param stops May be <code>null</code>. Valid values are between <code>0.0f</code> and + * <code>1.0f</code>. The relative position of each corresponding color in + * the colors array. If <code>null</code>, colors are distributed evenly + * between the center and edge of the circle. + * @param tileMode The Shader tiling mode + */ + public RadialGradient(float centerX, float centerY, float radius, + @NonNull @ColorInt int[] colors, @Nullable float[] stops, + @NonNull TileMode tileMode) { + this(centerX, centerY, radius, convertColors(colors), stops, tileMode, + ColorSpace.get(ColorSpace.Named.SRGB)); + } /** * Create a shader that draws a radial gradient given the center and radius. @@ -62,24 +80,36 @@ public class RadialGradient extends Shader { * the colors array. If <code>null</code>, colors are distributed evenly * between the center and edge of the circle. * @param tileMode The Shader tiling mode + * + * @throws IllegalArgumentException if there are less than two colors, the colors do + * not share the same {@link ColorSpace} or do not use a valid one, or {@code stops} + * is not {@code null} and has a different length from {@code colors}. */ public RadialGradient(float centerX, float centerY, float radius, - @NonNull @ColorInt int colors[], @Nullable float stops[], + @NonNull @ColorLong long[] colors, @Nullable float[] stops, @NonNull TileMode tileMode) { + this(centerX, centerY, radius, colors.clone(), stops, tileMode, detectColorSpace(colors)); + } + + /** + * Base constructor. Assumes @param colors is a copy that this object can hold onto, + * and all colors share @param colorSpace. + */ + private RadialGradient(float centerX, float centerY, float radius, + @NonNull @ColorLong long[] colors, @Nullable float[] stops, + @NonNull TileMode tileMode, ColorSpace colorSpace) { + super(colorSpace); + if (radius <= 0) { throw new IllegalArgumentException("radius must be > 0"); } - if (colors.length < 2) { - throw new IllegalArgumentException("needs >= 2 number of colors"); - } if (stops != null && colors.length != stops.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } - mType = TYPE_COLORS_AND_POSITIONS; mX = centerX; mY = centerY; mRadius = radius; - mColors = colors.clone(); + mColorLongs = colors; mPositions = stops != null ? stops.clone() : null; mTileMode = tileMode; } @@ -90,33 +120,38 @@ public class RadialGradient extends Shader { * @param centerX The x-coordinate of the center of the radius * @param centerY The y-coordinate of the center of the radius * @param radius Must be positive. The radius of the circle for this gradient + * @param centerColor The sRGB color at the center of the circle. + * @param edgeColor The sRGB color at the edge of the circle. + * @param tileMode The Shader tiling mode + */ + public RadialGradient(float centerX, float centerY, float radius, + @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode) { + this(centerX, centerY, radius, Color.pack(centerColor), Color.pack(edgeColor), tileMode); + } + + /** + * Create a shader that draws a radial gradient given the center and radius. + * + * @param centerX The x-coordinate of the center of the radius + * @param centerY The y-coordinate of the center of the radius + * @param radius Must be positive. The radius of the circle for this gradient * @param centerColor The color at the center of the circle. * @param edgeColor The color at the edge of the circle. * @param tileMode The Shader tiling mode + * + * @throws IllegalArgumentException if the colors do + * not share the same {@link ColorSpace} or do not use a valid one. */ public RadialGradient(float centerX, float centerY, float radius, - @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode) { - if (radius <= 0) { - throw new IllegalArgumentException("radius must be > 0"); - } - mType = TYPE_COLOR_CENTER_AND_COLOR_EDGE; - mX = centerX; - mY = centerY; - mRadius = radius; - mCenterColor = centerColor; - mEdgeColor = edgeColor; - mTileMode = tileMode; + @ColorLong long centerColor, @ColorLong long edgeColor, @NonNull TileMode tileMode) { + this(centerX, centerY, radius, new long[] {centerColor, edgeColor}, null, tileMode); } @Override long createNativeInstance(long nativeMatrix) { - if (mType == TYPE_COLORS_AND_POSITIONS) { - return nativeCreate1(nativeMatrix, mX, mY, mRadius, - mColors, mPositions, mTileMode.nativeInt); - } else { // TYPE_COLOR_CENTER_AND_COLOR_EDGE - return nativeCreate2(nativeMatrix, mX, mY, mRadius, - mCenterColor, mEdgeColor, mTileMode.nativeInt); - } + return nativeCreate(nativeMatrix, mX, mY, mRadius, + mColorLongs, mPositions, mTileMode.nativeInt, + colorSpace().getNativeInstance()); } /** @@ -124,20 +159,13 @@ public class RadialGradient extends Shader { */ @Override protected Shader copy() { - final RadialGradient copy; - if (mType == TYPE_COLORS_AND_POSITIONS) { - copy = new RadialGradient(mX, mY, mRadius, mColors.clone(), - mPositions != null ? mPositions.clone() : null, mTileMode); - } else { // TYPE_COLOR_CENTER_AND_COLOR_EDGE - copy = new RadialGradient(mX, mY, mRadius, mCenterColor, mEdgeColor, mTileMode); - } + final RadialGradient copy = new RadialGradient(mX, mY, mRadius, mColorLongs, + mPositions, mTileMode, colorSpace()); copyLocalMatrix(copy); return copy; } - private static native long nativeCreate1(long matrix, float x, float y, float radius, - int colors[], float positions[], int tileMode); - private static native long nativeCreate2(long matrix, float x, float y, float radius, - int color0, int color1, int tileMode); + private static native long nativeCreate(long matrix, float x, float y, float radius, + @ColorLong long[] colors, float[] positions, int tileMode, long colorSpaceHandle); } diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index 40bcc9e26a3d..7f097860196a 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -16,6 +16,8 @@ package android.graphics; +import android.annotation.ColorInt; +import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; @@ -39,7 +41,32 @@ public class Shader { * @deprecated Use subclass constructors directly instead. */ @Deprecated - public Shader() {} + public Shader() { + mColorSpace = null; + } + + /** + * @hide + */ + public Shader(ColorSpace colorSpace) { + mColorSpace = colorSpace; + if (colorSpace == null) { + throw new IllegalArgumentException( + "Use Shader() to create a Shader with no ColorSpace"); + } + + // This just ensures that if the ColorSpace is invalid, the Exception will be thrown now. + mColorSpace.getNativeInstance(); + } + + private final ColorSpace mColorSpace; + + /** + * @hide + */ + protected ColorSpace colorSpace() { + return mColorSpace; + } /** * Current native shader instance. Created and updated lazily when {@link #getNativeInstance()} @@ -169,6 +196,43 @@ public class Shader { return mNativeInstance; } + /** + * @hide + */ + public static @ColorLong long[] convertColors(@NonNull @ColorInt int[] colors) { + if (colors.length < 2) { + throw new IllegalArgumentException("needs >= 2 number of colors"); + } + + long[] colorLongs = new long[colors.length]; + for (int i = 0; i < colors.length; ++i) { + colorLongs[i] = Color.pack(colors[i]); + } + + return colorLongs; + } + + /** + * Detect the ColorSpace that the {@code colors} share. + * + * @throws IllegalArgumentException if the colors do not all share the same, + * valid ColorSpace, or if there are less than 2 colors. + * + * @hide + */ + public static ColorSpace detectColorSpace(@NonNull @ColorLong long[] colors) { + if (colors.length < 2) { + throw new IllegalArgumentException("needs >= 2 number of colors"); + } + final ColorSpace colorSpace = Color.colorSpace(colors[0]); + for (int i = 1; i < colors.length; ++i) { + if (Color.colorSpace(colors[i]) != colorSpace) { + throw new IllegalArgumentException("All colors must be in the same ColorSpace!"); + } + } + return colorSpace; + } + private static native long nativeGetFinalizer(); } diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java index f944d85d3cf2..fc386d7d598f 100644 --- a/graphics/java/android/graphics/SweepGradient.java +++ b/graphics/java/android/graphics/SweepGradient.java @@ -17,34 +17,52 @@ package android.graphics; import android.annotation.ColorInt; +import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; public class SweepGradient extends Shader { - - private static final int TYPE_COLORS_AND_POSITIONS = 1; - private static final int TYPE_COLOR_START_AND_COLOR_END = 2; - - /** - * Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or - * TYPE_COLOR_START_AND_COLOR_END. - */ - private int mType; - @UnsupportedAppUsage private float mCx; @UnsupportedAppUsage private float mCy; @UnsupportedAppUsage - private int[] mColors; - @UnsupportedAppUsage private float[] mPositions; + + // @ColorInts are replaced by @ColorLongs, but these remain due to @UnsupportedAppUsage. + @UnsupportedAppUsage + @ColorInt + private int[] mColors; @UnsupportedAppUsage + @ColorInt private int mColor0; @UnsupportedAppUsage + @ColorInt private int mColor1; + @ColorLong + private final long[] mColorLongs; + + /** + * A Shader that draws a sweep gradient around a center point. + * + * @param cx The x-coordinate of the center + * @param cy The y-coordinate of the center + * @param colors The sRGB colors to be distributed between around the center. + * There must be at least 2 colors in the array. + * @param positions May be NULL. The relative position of + * each corresponding color in the colors array, beginning + * with 0 and ending with 1.0. If the values are not + * monotonic, the drawing may produce unexpected results. + * If positions is NULL, then the colors are automatically + * spaced evenly. + */ + public SweepGradient(float cx, float cy, @NonNull @ColorInt int[] colors, + @Nullable float[] positions) { + this(cx, cy, convertColors(colors), positions, ColorSpace.get(ColorSpace.Named.SRGB)); + } + /** * A Shader that draws a sweep gradient around a center point. * @@ -58,20 +76,30 @@ public class SweepGradient extends Shader { * monotonic, the drawing may produce unexpected results. * If positions is NULL, then the colors are automatically * spaced evenly. + * @throws IllegalArgumentException if there are less than two colors, the colors do + * not share the same {@link ColorSpace} or do not use a valid one, or {@code positions} + * is not {@code null} and has a different length from {@code colors}. */ - public SweepGradient(float cx, float cy, - @NonNull @ColorInt int colors[], @Nullable float positions[]) { - if (colors.length < 2) { - throw new IllegalArgumentException("needs >= 2 number of colors"); - } + public SweepGradient(float cx, float cy, @NonNull @ColorLong long[] colors, + @Nullable float[] positions) { + this(cx, cy, colors.clone(), positions, detectColorSpace(colors)); + } + + /** + * Base constructor. Assumes @param colors is a copy that this object can hold onto, + * and all colors share @param colorSpace. + */ + private SweepGradient(float cx, float cy, @NonNull @ColorLong long[] colors, + @Nullable float[] positions, ColorSpace colorSpace) { + super(colorSpace); + if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException( "color and position arrays must be of equal length"); } - mType = TYPE_COLORS_AND_POSITIONS; mCx = cx; mCy = cy; - mColors = colors.clone(); + mColorLongs = colors; mPositions = positions != null ? positions.clone() : null; } @@ -80,26 +108,32 @@ public class SweepGradient extends Shader { * * @param cx The x-coordinate of the center * @param cy The y-coordinate of the center + * @param color0 The sRGB color to use at the start of the sweep + * @param color1 The sRGB color to use at the end of the sweep + */ + public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) { + this(cx, cy, Color.pack(color0), Color.pack(color1)); + } + + /** + * A Shader that draws a sweep gradient around a center point. + * + * @param cx The x-coordinate of the center + * @param cy The y-coordinate of the center * @param color0 The color to use at the start of the sweep * @param color1 The color to use at the end of the sweep + * + * @throws IllegalArgumentException if the colors do + * not share the same {@link ColorSpace} or do not use a valid one. */ - public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) { - mType = TYPE_COLOR_START_AND_COLOR_END; - mCx = cx; - mCy = cy; - mColor0 = color0; - mColor1 = color1; - mColors = null; - mPositions = null; + public SweepGradient(float cx, float cy, @ColorLong long color0, @ColorLong long color1) { + this(cx, cy, new long[] {color0, color1}, null); } @Override long createNativeInstance(long nativeMatrix) { - if (mType == TYPE_COLORS_AND_POSITIONS) { - return nativeCreate1(nativeMatrix, mCx, mCy, mColors, mPositions); - } else { // TYPE_COLOR_START_AND_COLOR_END - return nativeCreate2(nativeMatrix, mCx, mCy, mColor0, mColor1); - } + return nativeCreate(nativeMatrix, mCx, mCy, mColorLongs, mPositions, + colorSpace().getNativeInstance()); } /** @@ -107,20 +141,13 @@ public class SweepGradient extends Shader { */ @Override protected Shader copy() { - final SweepGradient copy; - if (mType == TYPE_COLORS_AND_POSITIONS) { - copy = new SweepGradient(mCx, mCy, mColors.clone(), - mPositions != null ? mPositions.clone() : null); - } else { // TYPE_COLOR_START_AND_COLOR_END - copy = new SweepGradient(mCx, mCy, mColor0, mColor1); - } + final SweepGradient copy = new SweepGradient(mCx, mCy, mColorLongs, + mPositions, colorSpace()); copyLocalMatrix(copy); return copy; } - private static native long nativeCreate1(long matrix, float x, float y, - int colors[], float positions[]); - private static native long nativeCreate2(long matrix, float x, float y, - int color0, int color1); + private static native long nativeCreate(long matrix, float x, float y, + long[] colors, float[] positions, long colorSpaceHandle); } diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index b67aea224055..d9456355cb88 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -142,10 +142,8 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { FunctorDrawable* functorDrawable; if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the - // interop is disabled. functorDrawable = - mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor, asSkCanvas()); + mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas()); } else { functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas()); } diff --git a/media/java/android/media/session/ControllerCallbackLink.java b/media/java/android/media/session/ControllerCallbackLink.java index adc14a550b7d..428be0db778e 100644 --- a/media/java/android/media/session/ControllerCallbackLink.java +++ b/media/java/android/media/session/ControllerCallbackLink.java @@ -20,7 +20,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SystemApi; import android.content.Context; import android.content.pm.PackageManager; import android.media.MediaMetadata; @@ -41,7 +40,6 @@ import java.util.List; * Handles incoming commands to {@link MediaController.Callback}. * @hide */ -@SystemApi public final class ControllerCallbackLink implements Parcelable { final Context mContext; final CallbackStub mCallbackStub; diff --git a/media/java/android/media/session/ControllerLink.java b/media/java/android/media/session/ControllerLink.java index f60ec000f2d2..64d283f168e1 100644 --- a/media/java/android/media/session/ControllerLink.java +++ b/media/java/android/media/session/ControllerLink.java @@ -18,7 +18,6 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.app.PendingIntent; import android.media.MediaMetadata; import android.media.MediaParceledListSlice; @@ -40,7 +39,6 @@ import java.util.Objects; * Handles incoming commands from {@link MediaController}. * @hide */ -@SystemApi public final class ControllerLink implements Parcelable { public static final Parcelable.Creator<ControllerLink> CREATOR = new Parcelable.Creator<ControllerLink>() { diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 1333ab097219..6e2c8c51c734 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -413,6 +413,7 @@ public final class MediaController { * Get the session's tag for debugging purposes. * * @return The session's tag. + * @hide */ public String getTag() { if (mTag == null) { diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 03627de9343c..1b9ebdafd328 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -19,7 +19,6 @@ package android.media.session; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; @@ -487,7 +486,6 @@ public final class MediaSession { * Gets the controller link in this token. * @hide */ - @SystemApi public ControllerLink getControllerLink() { return mControllerLink; } @@ -696,7 +694,6 @@ public final class MediaSession { /** * @hide */ - @SystemApi public void onSetMediaButtonEventDelegate( @NonNull MediaSessionEngine.MediaButtonEventDelegate delegate) { mMediaButtonEventDelegate = delegate; diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java index 7fea90dd0c43..e19bdbcf923e 100644 --- a/media/java/android/media/session/MediaSessionEngine.java +++ b/media/java/android/media/session/MediaSessionEngine.java @@ -18,7 +18,6 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.app.Activity; import android.app.PendingIntent; import android.content.Context; @@ -49,7 +48,6 @@ import java.util.Objects; /** * @hide */ -@SystemApi public final class MediaSessionEngine implements AutoCloseable { private static final String TAG = "MediaSession"; diff --git a/media/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java index 4c2918a0fa94..f59a69d6e157 100644 --- a/media/java/android/media/session/SessionCallbackLink.java +++ b/media/java/android/media/session/SessionCallbackLink.java @@ -20,7 +20,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -42,7 +41,6 @@ import java.lang.ref.WeakReference; * Handles incoming commands to {@link MediaSession.Callback}. * @hide */ -@SystemApi public final class SessionCallbackLink implements Parcelable { final Context mContext; final ISessionCallback mISessionCallback; diff --git a/media/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java index 4ea762367010..2331a4a0ab52 100644 --- a/media/java/android/media/session/SessionLink.java +++ b/media/java/android/media/session/SessionLink.java @@ -18,7 +18,6 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.app.PendingIntent; import android.media.AudioAttributes; import android.media.MediaMetadata; @@ -36,7 +35,6 @@ import java.util.List; * Handles incoming commands from {@link MediaSession}. * @hide */ -@SystemApi public final class SessionLink implements Parcelable { public static final Parcelable.Creator<SessionLink> CREATOR = new Parcelable.Creator<SessionLink>() { diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp index 6deb47f09347..e43a60c3f396 100644 --- a/native/webview/plat_support/draw_functor.cpp +++ b/native/webview/plat_support/draw_functor.cpp @@ -177,9 +177,6 @@ int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) { webview_functor_callbacks.vk.initialize = &initializeVk; webview_functor_callbacks.vk.draw = &drawVk; webview_functor_callbacks.vk.postDraw = &postDrawVk; - // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor - // no longer uses GL interop. - webview_functor_callbacks.gles.draw = &draw_gl; break; } callbacks_initialized = true; diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index 5317a6df53e8..66d5d1160bf6 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -27,7 +27,7 @@ import com.android.systemui.plugins.annotations.ProvidesInterface; */ @ProvidesInterface(version = ActivityStarter.VERSION) public interface ActivityStarter { - int VERSION = 1; + int VERSION = 2; void startPendingIntentDismissingKeyguard(PendingIntent intent); @@ -37,6 +37,11 @@ public interface ActivityStarter { */ void startPendingIntentDismissingKeyguard(PendingIntent intent, Runnable intentSentUiThreadCallback); + + /** + * The intent flag can be specified in startActivity(). + */ + void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags); void startActivity(Intent intent, boolean dismissShade); void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade); void startActivity(Intent intent, boolean dismissShade, Callback callback); diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java index b461f69f10d6..04f887bb6b2f 100644 --- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java @@ -53,6 +53,15 @@ public class ActivityStarterDelegate implements ActivityStarter { } @Override + public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, + int flags) { + if (mActualStarter == null) { + return; + } + mActualStarter.startActivity(intent, onlyProvisioned, dismissShade, flags); + } + + @Override public void startActivity(Intent intent, boolean dismissShade) { if (mActualStarter == null) { return; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java index 71ae1f8620f6..231e725057d0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java @@ -19,6 +19,7 @@ package com.android.systemui.bubbles; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.ShapeDrawable; import android.text.TextUtils; @@ -68,9 +69,15 @@ public class BubbleExpandedViewContainer extends LinearLayout { mPointerView = findViewById(R.id.pointer_view); int width = res.getDimensionPixelSize(R.dimen.bubble_pointer_width); int height = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); + + TypedArray ta = getContext().obtainStyledAttributes( + new int[] {android.R.attr.colorBackgroundFloating}); + int bgColor = ta.getColor(0, Color.WHITE); + ta.recycle(); + ShapeDrawable triangleDrawable = new ShapeDrawable( TriangleShape.create(width, height, true /* pointUp */)); - triangleDrawable.setTint(Color.WHITE); // TODO: dark mode + triangleDrawable.setTint(bgColor); mPointerView.setBackground(triangleDrawable); mHeaderView = findViewById(R.id.bubble_content_header); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 8731bd52e0dd..cbca2fce6b35 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -237,6 +237,10 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F * Sets the bubble that should be expanded and expands if needed. */ public void setExpandedBubble(BubbleView bubbleToExpand) { + if (mIsExpanded && !bubbleToExpand.equals(mExpandedBubble)) { + // Previously expanded, notify that this bubble is no longer expanded + notifyExpansionChanged(mExpandedBubble, false /* expanded */); + } mExpandedBubble = bubbleToExpand; if (!mIsExpanded) { // If we weren't previously expanded we should animate open. @@ -291,12 +295,12 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F int nextIndex = bubbleCount > removedIndex ? removedIndex : bubbleCount - 1; BubbleView expandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex); setExpandedBubble(expandedBubble); + requestUpdate(); } mIsExpanded = wasExpanded && mBubbleContainer.getChildCount() > 0; if (wasExpanded != mIsExpanded) { notifyExpansionChanged(mExpandedBubble, mIsExpanded); } - requestUpdate(); } /** @@ -373,9 +377,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F public void expandStack() { if (!mIsExpanded) { mExpandedBubble = getTopBubble(); - mExpandedBubble.getEntry().setShowInShadeWhenBubble(false); - animateExpansion(true /* shouldExpand */); - notifyExpansionChanged(mExpandedBubble, true /* expanded */); + setExpandedBubble(mExpandedBubble); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 562edd61c867..675948e5c4d7 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -130,7 +130,7 @@ public class DozeSensors { false /* touchscreen */), new PluginSensor( new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN), - Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, + Settings.Secure.DOZE_WAKE_SCREEN_GESTURE, mConfig.wakeScreenGestureAvailable(), DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, false /* reports touch coordinates */, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java new file mode 100644 index 000000000000..752b6a80f93d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java @@ -0,0 +1,99 @@ +/* + * 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 android.content.Context; +import android.content.Intent; +import android.service.notification.StatusBarNotification; +import android.util.FeatureFlagUtils; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; + +import com.android.settingslib.media.MediaOutputSliceConstants; +import com.android.systemui.Dependency; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; + +/** + * Class for handling MediaTransfer state over a set of notifications. + */ +public class MediaTransferManager { + private final Context mContext; + private final ActivityStarter mActivityStarter; + + private final View.OnClickListener mOnClickHandler = new View.OnClickListener() { + @Override + public void onClick(View view) { + if (handleMediaTransfer(view)) { + return; + } + } + + private boolean handleMediaTransfer(View view) { + if (view.findViewById(com.android.internal.R.id.media_seamless) == null) { + return false; + } + + ViewParent parent = view.getParent(); + StatusBarNotification statusBarNotification = getNotificationForParent(parent); + final Intent intent = new Intent() + .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, + statusBarNotification.getPackageName()); + mActivityStarter.startActivity(intent, false, true /* dismissShade */, + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + return true; + } + + private StatusBarNotification getNotificationForParent(ViewParent parent) { + while (parent != null) { + if (parent instanceof ExpandableNotificationRow) { + return ((ExpandableNotificationRow) parent).getStatusBarNotification(); + } + parent = parent.getParent(); + } + return null; + } + }; + + public MediaTransferManager(Context context) { + mContext = context; + mActivityStarter = Dependency.get(ActivityStarter.class); + } + + /** + * apply the action button for MediaTransfer + * + * @param root The parent container of the view. + * @param entry The entry of MediaTransfer action button. + */ + public void applyMediaTransferView(ViewGroup root, NotificationEntry entry) { + if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)) { + return; + } + + View view = root.findViewById(com.android.internal.R.id.media_seamless); + if (view == null) { + return; + } + + view.setVisibility(View.VISIBLE); + view.setOnClickListener(mOnClickHandler); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index c161da348c28..77cdbb921273 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -43,6 +43,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.statusbar.MediaTransferManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.TransformableView; @@ -163,11 +164,13 @@ public class NotificationContentView extends FrameLayout { private boolean mIsContentExpandable; private boolean mRemoteInputVisible; private int mUnrestrictedContentHeight; + private MediaTransferManager mMediaTransferManager; public NotificationContentView(Context context, AttributeSet attrs) { super(context, attrs); mHybridGroupManager = new HybridGroupManager(getContext(), this); + mMediaTransferManager = new MediaTransferManager(getContext()); mSmartReplyConstants = Dependency.get(SmartReplyConstants.class); mSmartReplyController = Dependency.get(SmartReplyController.class); initView(); @@ -1250,6 +1253,7 @@ public class NotificationContentView extends FrameLayout { mAmbientWrapper.onContentUpdated(row); } applyRemoteInputAndSmartReply(entry); + applyMediaTransfer(entry); updateLegacy(); mForceSelectNextLayout = true; setDark(mDark, false /* animate */, 0 /* delay */); @@ -1292,6 +1296,22 @@ public class NotificationContentView extends FrameLayout { } } + private void applyMediaTransfer(final NotificationEntry entry) { + View bigContentView = mExpandedChild; + if (bigContentView == null || !entry.isMediaNotification()) { + return; + } + + View mediaActionContainer = bigContentView.findViewById( + com.android.internal.R.id.media_actions); + if (!(mediaActionContainer instanceof LinearLayout)) { + return; + } + + mMediaTransferManager.applyMediaTransferView((ViewGroup) mediaActionContainer, + entry); + } + private void applyRemoteInputAndSmartReply(final NotificationEntry entry) { if (mRemoteInputController == null) { return; 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 dd231821ef2b..241326850090 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1444,6 +1444,7 @@ public class StatusBar extends SystemUI implements DemoMode, return new StatusBar.H(); } + @Override public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags) { startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags); 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 6a3bd735fc61..5be8826f92b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -77,6 +77,10 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private NotificationData mNotificationData; + @Mock + private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener; + @Mock + private BubbleController.BubbleExpandListener mBubbleExpandListener; @Before public void setUp() throws Exception { @@ -101,6 +105,8 @@ public class BubbleControllerTest extends SysuiTestCase { when(mNotificationData.getChannel(mNoChannelRow.getEntry().key)).thenReturn(null); mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController); + mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); + mBubbleController.setExpandListener(mBubbleExpandListener); // Get a reference to the BubbleController's entry listener verify(mNotificationEntryManager, atLeastOnce()) @@ -112,6 +118,8 @@ public class BubbleControllerTest extends SysuiTestCase { public void testAddBubble() { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); assertTrue(mBubbleController.hasBubbles()); + + verify(mBubbleStateChangeListener).onHasBubblesChanged(true); } @Test @@ -126,10 +134,14 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); assertTrue(mBubbleController.hasBubbles()); + verify(mBubbleStateChangeListener).onHasBubblesChanged(true); + mBubbleController.removeBubble(mRow.getEntry().key); assertFalse(mStatusBarWindowController.getBubblesShowing()); assertTrue(mRow.getEntry().isBubbleDismissed()); verify(mNotificationEntryManager).updateNotifications(); + + verify(mBubbleStateChangeListener).onHasBubblesChanged(false); } @Test @@ -141,41 +153,133 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.dismissStack(); assertFalse(mStatusBarWindowController.getBubblesShowing()); verify(mNotificationEntryManager).updateNotifications(); + assertTrue(mRow.getEntry().isBubbleDismissed()); + assertTrue(mRow2.getEntry().isBubbleDismissed()); } @Test - public void testIsStackExpanded() { + public void testExpandCollapseStack() { assertFalse(mBubbleController.isStackExpanded()); + + // Mark it as a bubble and add it explicitly + mEntryListener.onPendingEntryAdded(mRow.getEntry()); mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); + // We should have bubbles & their notifs should show in the shade + assertTrue(mBubbleController.hasBubbles()); + assertTrue(mRow.getEntry().showInShadeWhenBubble()); + + // Expand the stack BubbleStackView stackView = mBubbleController.getStackView(); stackView.expandStack(); assertTrue(mBubbleController.isStackExpanded()); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); + + // Make sure it's no longer in the shade + assertFalse(mRow.getEntry().showInShadeWhenBubble()); + // Collapse stackView.collapseStack(); + verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); assertFalse(mBubbleController.isStackExpanded()); } @Test - public void testCollapseStack() { + public void testCollapseAfterChangingExpandedBubble() { + // Mark it as a bubble and add it explicitly + mEntryListener.onPendingEntryAdded(mRow.getEntry()); + mEntryListener.onPendingEntryAdded(mRow2.getEntry()); mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */); + // We should have bubbles & their notifs should show in the shade + assertTrue(mBubbleController.hasBubbles()); + assertTrue(mRow.getEntry().showInShadeWhenBubble()); + assertTrue(mRow2.getEntry().showInShadeWhenBubble()); + + // Expand BubbleStackView stackView = mBubbleController.getStackView(); stackView.expandStack(); assertTrue(mBubbleController.isStackExpanded()); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key); + + // Last added is the one that is expanded + assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry()); + assertFalse(mRow2.getEntry().showInShadeWhenBubble()); + // Switch which bubble is expanded stackView.setExpandedBubble(mRow.getEntry()); - assertEquals(stackView.getExpandedBubble().getEntry(), mRow.getEntry()); + assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry()); + assertFalse(mRow.getEntry().showInShadeWhenBubble()); - stackView.setExpandedBubble(mRow2.getEntry()); - assertEquals(stackView.getExpandedBubble().getEntry(), mRow2.getEntry()); + // collapse for previous bubble + verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key); + // expand for selected bubble + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); + // Collapse mBubbleController.collapseStack(); assertFalse(mBubbleController.isStackExpanded()); } @Test + public void testExpansionRemovesShowInShade() { + // Mark it as a bubble and add it explicitly + mEntryListener.onPendingEntryAdded(mRow.getEntry()); + mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); + + // We should have bubbles & their notifs should show in the shade + assertTrue(mBubbleController.hasBubbles()); + assertTrue(mRow.getEntry().showInShadeWhenBubble()); + + // Expand + BubbleStackView stackView = mBubbleController.getStackView(); + stackView.expandStack(); + assertTrue(mBubbleController.isStackExpanded()); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); + + // No longer show shade in notif after expansion + assertFalse(mRow.getEntry().showInShadeWhenBubble()); + } + + @Test + public void testRemoveLastExpandedCollapses() { + // Mark it as a bubble and add it explicitly + mEntryListener.onPendingEntryAdded(mRow.getEntry()); + mEntryListener.onPendingEntryAdded(mRow2.getEntry()); + mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); + mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */); + verify(mBubbleStateChangeListener).onHasBubblesChanged(true); + + // Expand + BubbleStackView stackView = mBubbleController.getStackView(); + stackView.expandStack(); + + assertTrue(mBubbleController.isStackExpanded()); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key); + + // Last added is the one that is expanded + assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry()); + assertFalse(mRow2.getEntry().showInShadeWhenBubble()); + + // Dismiss currently expanded + mBubbleController.removeBubble(stackView.getExpandedBubble().getKey()); + verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key); + + // Make sure next bubble is selected + assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry()); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); + + // Dismiss that one + mBubbleController.removeBubble(stackView.getExpandedBubble().getKey()); + + // Make sure state changes and collapse happens + verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); + verify(mBubbleStateChangeListener).onHasBubblesChanged(false); + assertFalse(mBubbleController.hasBubbles()); + } + + @Test public void testMarkNewNotificationAsBubble() { mEntryListener.onPendingEntryAdded(mRow.getEntry()); assertTrue(mRow.getEntry().isBubble()); diff --git a/packages/overlays/FontArbutusSourceOverlay/Android.mk b/packages/overlays/FontArbutusSourceOverlay/Android.mk deleted file mode 100644 index 23aee558257a..000000000000 --- a/packages/overlays/FontArbutusSourceOverlay/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2018, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_RRO_THEME := FontArbutusSource -LOCAL_CERTIFICATE := platform -LOCAL_PRODUCT_MODULE := true - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - -LOCAL_PACKAGE_NAME := FontArbutusSourceOverlay -LOCAL_SDK_VERSION := current - -include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml b/packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml deleted file mode 100644 index 46c06b969461..000000000000 --- a/packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.theme.font.arbutussource" - android:versionCode="1" - android:versionName="1.0"> - <overlay android:targetPackage="android" - android:category="android.theme.customization.font" - android:priority="1"/> - - <application android:label="@string/font_arbutus_source_overlay" android:hasCode="false"> - <meta-data - android:name="android.theme.customization.REQUIRED_SYSTEM_FONTS" - android:value="arbutus-slab,source-sans-pro,source-sans-pro-medium" /> - </application> -</manifest> diff --git a/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml b/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml deleted file mode 100644 index a6aa64c03c50..000000000000 --- a/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Name of a font family to use for body text. --> - <string name="config_bodyFontFamily" translatable="false">source-sans-pro</string> - <!-- Name of a font family to use for medium body text. --> - <string name="config_bodyFontFamilyMedium" translatable="false">source-sans-pro-semi-bold</string> - <!-- Name of a font family to use for headlines. If empty, falls back to platform default --> - <string name="config_headlineFontFamily" translatable="false">arbutus-slab</string> - <!-- Name of the font family used for system surfaces where the font should use medium weight --> - <string name="config_headlineFontFamilyMedium" translatable="false">arbutus-slab</string> -</resources> - diff --git a/packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml b/packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml deleted file mode 100644 index d80eb20677c1..000000000000 --- a/packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Headline / Body font Arbutus Slab / Source Sans Pro overlay --> - <string name="font_arbutus_source_overlay" translatable="false">Arbutus Slab / Source Sans Pro</string> -</resources> diff --git a/packages/overlays/FontArvoLatoOverlay/Android.mk b/packages/overlays/FontArvoLatoOverlay/Android.mk deleted file mode 100644 index 3433ecfd1f6b..000000000000 --- a/packages/overlays/FontArvoLatoOverlay/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2018, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_RRO_THEME := FontArvoLato -LOCAL_CERTIFICATE := platform -LOCAL_PRODUCT_MODULE := true - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - -LOCAL_PACKAGE_NAME := FontArvoLatoOverlay -LOCAL_SDK_VERSION := current - -include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml b/packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml deleted file mode 100644 index 3f2e5de39c0b..000000000000 --- a/packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.theme.font.arvolato" - android:versionCode="1" - android:versionName="1.0"> - <overlay android:targetPackage="android" - android:category="android.theme.customization.font" - android:priority="1"/> - - <application android:label="@string/font_arvo_lato_overlay" android:hasCode="false"> - <meta-data - android:name="android.theme.customization.REQUIRED_SYSTEM_FONTS" - android:value="arvo,arvo-medium,lato,lato-medium" /> - </application> -</manifest> diff --git a/packages/overlays/FontArvoLatoOverlay/res/values/config.xml b/packages/overlays/FontArvoLatoOverlay/res/values/config.xml deleted file mode 100644 index 4e70d72aaae8..000000000000 --- a/packages/overlays/FontArvoLatoOverlay/res/values/config.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Name of a font family to use for body text. --> - <string name="config_bodyFontFamily" translatable="false">lato</string> - <!-- Name of a font family to use for medium body text. --> - <string name="config_bodyFontFamilyMedium" translatable="false">lato-bold</string> - <!-- Name of a font family to use for headlines. If empty, falls back to platform default --> - <string name="config_headlineFontFamily" translatable="false">arvo</string> - <!-- Name of the font family used for system surfaces where the font should use medium weight --> - <string name="config_headlineFontFamilyMedium" translatable="false">arvo-bold</string> -</resources> - diff --git a/packages/overlays/FontArvoLatoOverlay/res/values/strings.xml b/packages/overlays/FontArvoLatoOverlay/res/values/strings.xml deleted file mode 100644 index 9ea097f1fe48..000000000000 --- a/packages/overlays/FontArvoLatoOverlay/res/values/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Headline / Body font Arvo / Lato overlay --> - <string name="font_arvo_lato_overlay" translatable="false">Arvo / Lato</string> -</resources> diff --git a/packages/overlays/FontRubikRubikOverlay/Android.mk b/packages/overlays/FontRubikRubikOverlay/Android.mk deleted file mode 100644 index 21d617ef2c72..000000000000 --- a/packages/overlays/FontRubikRubikOverlay/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2018, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_RRO_THEME := FontRubikRubik -LOCAL_CERTIFICATE := platform -LOCAL_PRODUCT_MODULE := true - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - -LOCAL_PACKAGE_NAME := FontRubikRubikOverlay -LOCAL_SDK_VERSION := current - -include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml b/packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml deleted file mode 100644 index 1f28d46f087a..000000000000 --- a/packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.theme.font.rubikrubik" - android:versionCode="1" - android:versionName="1.0"> - <overlay android:targetPackage="android" - android:category="android.theme.customization.font" - android:priority="1"/> - - <application android:label="@string/font_rubik_rubik_overlay" android:hasCode="false"> - <meta-data - android:name="android.theme.customization.REQUIRED_SYSTEM_FONTS" - android:value="rubik,rubik-medium" /> - </application> -</manifest> diff --git a/packages/overlays/FontRubikRubikOverlay/res/values/config.xml b/packages/overlays/FontRubikRubikOverlay/res/values/config.xml deleted file mode 100644 index 4f90e292e2f4..000000000000 --- a/packages/overlays/FontRubikRubikOverlay/res/values/config.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Name of a font family to use for body text. --> - <string name="config_bodyFontFamily" translatable="false">rubik</string> - <!-- Name of a font family to use for medium body text. --> - <string name="config_bodyFontFamilyMedium" translatable="false">rubik-medium</string> - <!-- Name of a font family to use for headlines. If empty, falls back to platform default --> - <string name="config_headlineFontFamily" translatable="false">rubik</string> - <!-- Name of the font family used for system surfaces where the font should use medium weight --> - <string name="config_headlineFontFamilyMedium" translatable="false">rubik-medium</string> -</resources> - diff --git a/packages/overlays/FontRubikRubikOverlay/res/values/strings.xml b/packages/overlays/FontRubikRubikOverlay/res/values/strings.xml deleted file mode 100644 index 4bac7da0aa73..000000000000 --- a/packages/overlays/FontRubikRubikOverlay/res/values/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ -<!-- -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Headline / Body font Rubik overlay --> - <string name="font_rubik_rubik_overlay" translatable="false">Rubik / Rubik</string> -</resources> diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 7e95f10752bd..e1af81b2f658 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -166,6 +166,7 @@ public class Vpn { private final NetworkInfo mNetworkInfo; private String mPackage; private int mOwnerUID; + private boolean mIsPackageTargetingAtLeastQ; private String mInterface; private Connection mConnection; private LegacyVpnRunner mLegacyVpnRunner; @@ -227,6 +228,7 @@ public class Vpn { mPackage = VpnConfig.LEGACY_VPN; mOwnerUID = getAppUid(mPackage, mUserHandle); + mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage); try { netService.registerObserver(mObserver); @@ -268,8 +270,11 @@ public class Vpn { public void updateCapabilities() { final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null; + // Only apps targeting Q and above can explicitly declare themselves as metered. + final boolean isAlwaysMetered = + mIsPackageTargetingAtLeastQ && (mConfig == null || mConfig.isMetered); updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks, - mNetworkCapabilities); + mNetworkCapabilities, isAlwaysMetered); if (mNetworkAgent != null) { mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); @@ -278,11 +283,13 @@ public class Vpn { @VisibleForTesting public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks, - NetworkCapabilities caps) { + NetworkCapabilities caps, boolean isAlwaysMetered) { int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; - boolean metered = false; + // VPN's meteredness is OR'd with isAlwaysMetered and meteredness of its underlying + // networks. + boolean metered = isAlwaysMetered; boolean roaming = false; boolean congested = false; @@ -725,6 +732,7 @@ public class Vpn { Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); mPackage = newPackage; mOwnerUID = getAppUid(newPackage, mUserHandle); + mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage); try { mNetd.allowProtect(mOwnerUID); } catch (Exception e) { @@ -790,6 +798,21 @@ public class Vpn { return result; } + private boolean doesPackageTargetAtLeastQ(String packageName) { + if (VpnConfig.LEGACY_VPN.equals(packageName)) { + return true; + } + PackageManager pm = mContext.getPackageManager(); + try { + ApplicationInfo appInfo = + pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle); + return appInfo.targetSdkVersion >= VERSION_CODES.Q; + } catch (NameNotFoundException unused) { + Log.w(TAG, "Can't find \"" + packageName + "\""); + return false; + } + } + public NetworkInfo getNetworkInfo() { return mNetworkInfo; } @@ -1078,6 +1101,8 @@ public class Vpn { // as rules are deleted. This prevents data leakage as the rules are moved over. agentDisconnect(oldNetworkAgent); } + // Set up VPN's capabilities such as meteredness. + updateCapabilities(); if (oldConnection != null) { mContext.unbindService(oldConnection); @@ -1778,6 +1803,7 @@ public class Vpn { config.user = profile.key; config.interfaze = iface; config.session = profile.name; + config.isMetered = false; config.addLegacyRoutes(profile.routes); if (!profile.dnsServers.isEmpty()) { diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 60d792530101..33b8641c145e 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -51,6 +51,8 @@ per-file UserManagerService.java = omakoto@google.com per-file UserManagerService.java = yamasani@google.com per-file UserRestrictionsUtils.java = omakoto@google.com per-file UserRestrictionsUtils.java = yamasani@google.com +per-file UserRestrictionsUtils.java = rubinxu@google.com +per-file UserRestrictionsUtils.java = sandness@google.com # security per-file KeySetHandle.java = cbrubaker@google.com diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index a2c8dace9510..4186154016e2 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -24,11 +24,13 @@ import android.os.PowerManagerInternal; import android.os.SystemClock; import android.service.attention.AttentionService; import android.util.Slog; +import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicLong; /** * Class responsible for checking if the user is currently paying attention to the phone and @@ -79,6 +81,11 @@ public class AttentionDetector { */ private int mWakefulness; + /** + * Describes how many times in a row was the timeout extended. + */ + private AtomicLong mConsecutiveTimeoutExtendedCount = new AtomicLong(0); + @VisibleForTesting final AttentionCallbackInternal mCallback = new AttentionCallbackInternal() { @@ -95,6 +102,8 @@ public class AttentionDetector { } if (result == AttentionService.ATTENTION_SUCCESS_PRESENT) { mOnUserAttention.run(); + } else { + resetConsecutiveExtensionCount(); } } } @@ -176,6 +185,7 @@ public class AttentionDetector { public int onUserActivity(long eventTime, int event) { switch (event) { case PowerManager.USER_ACTIVITY_EVENT_ATTENTION: + mConsecutiveTimeoutExtendedCount.incrementAndGet(); return 0; case PowerManager.USER_ACTIVITY_EVENT_OTHER: case PowerManager.USER_ACTIVITY_EVENT_BUTTON: @@ -183,6 +193,7 @@ public class AttentionDetector { case PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY: cancelCurrentRequestIfAny(); mLastUserActivityTime = eventTime; + resetConsecutiveExtensionCount(); return 1; default: if (DEBUG) { @@ -196,6 +207,7 @@ public class AttentionDetector { mWakefulness = wakefulness; if (wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) { cancelCurrentRequestIfAny(); + resetConsecutiveExtensionCount(); } } @@ -206,6 +218,13 @@ public class AttentionDetector { } } + private void resetConsecutiveExtensionCount() { + final long previousCount = mConsecutiveTimeoutExtendedCount.getAndSet(0); + if (previousCount > 0) { + StatsLog.write(StatsLog.SCREEN_TIMEOUT_EXTENSION_REPORTED, previousCount); + } + } + @VisibleForTesting int getRequestCode() { return (int) (mLastUserActivityTime % Integer.MAX_VALUE); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0e63b2b4db4d..a1fb09017bcd 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -72,6 +72,7 @@ import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.annotations.VisibleForTesting; @@ -3264,6 +3265,35 @@ public class TelephonyManager { } } + /** + * Get the mapping from logical slots to physical slots. The mapping represent by a pair list. + * The key of the piar is the logical slot id and the value of the pair is the physical + * slots id mapped to this logical slot id. + * + * @return an pair list indicates the mapping from logical slots to physical slots. The size of + * the list should be {@link #getPhoneCount()} if success, otherwise return an empty list. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @NonNull + public List<Pair<Integer, Integer>> getLogicalToPhysicalSlotMapping() { + List<Pair<Integer, Integer>> slotMapping = new ArrayList<>(); + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + int[] slotMappingArray = telephony.getSlotsMapping(); + for (int i = 0; i < slotMappingArray.length; i++) { + slotMapping.add(new Pair(i, slotMappingArray[i])); + } + } + } catch (RemoteException e) { + Log.e(TAG, "getSlotsMapping RemoteException", e); + } + return slotMapping; + } + // // // Subscriber Info diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index bca088e618c0..b2f5802db597 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -464,7 +464,7 @@ public class EuiccManager { return null; } try { - return getIEuiccController().getEid(mCardId); + return getIEuiccController().getEid(mCardId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -502,6 +502,15 @@ public class EuiccManager { * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be * returned in the callback intent to prompt the user to accept the download. * + * <p>On a multi-active SIM device, requires the + * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app + * only if the targeted eUICC does not currently have an active subscription or the calling app + * is authorized to manage the active subscription on the target eUICC, and the calling app is + * authorized to manage any active subscription on any SIM. Without it, an + * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback + * intent to prompt the user to accept the download. The caller should also be authorized to + * manage the subscription to be downloaded. + * * @param subscription the subscription to download. * @param switchAfterDownload if true, the profile will be activated upon successful download. * @param callbackIntent a PendingIntent to launch when the operation completes. @@ -704,9 +713,21 @@ public class EuiccManager { * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback * intent to prompt the user to accept the download. * + * <p>On a multi-active SIM device, requires the + * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app + * only if the targeted eUICC does not currently have an active subscription or the calling app + * is authorized to manage the active subscription on the target eUICC, and the calling app is + * authorized to manage any active subscription on any SIM. Without it, an + * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback + * intent to prompt the user to accept the download. The caller should also be authorized to + * manage the subscription to be enabled. + * * @param subscriptionId the ID of the subscription to enable. May be * {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the - * current profile without activating another profile to replace it. + * current profile without activating another profile to replace it. If it's a disable + * operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} + * permission, or the calling app must be authorized to manage the active subscription on + * the target eUICC. * @param callbackIntent a PendingIntent to launch when the operation completes. */ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 62f9999bc924..762d8860afcd 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1848,8 +1848,14 @@ interface ITelephony { * @hide */ int getNumOfActiveSims(); + /** * Get if reboot is required upon altering modems configurations */ boolean isRebootRequiredForModemConfigChange(); + + /** + * Get the mapping from logical slots to physical slots. + */ + int[] getSlotsMapping(); } diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl index 14a36c8c840d..20169152539e 100644 --- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl @@ -31,7 +31,7 @@ interface IEuiccController { String callingPackage, in PendingIntent callbackIntent); oneway void getDefaultDownloadableSubscriptionList(int cardId, String callingPackage, in PendingIntent callbackIntent); - String getEid(int cardId); + String getEid(int cardId, String callingPackage); int getOtaStatus(int cardId); oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 3127d745b55d..50468cbe7050 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -922,6 +922,7 @@ public class ConnectivityServiceTest { mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); mConnected = true; mConfig = new VpnConfig(); + mConfig.isMetered = false; } @Override diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 5b17224e41e5..46de3d0608ff 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -168,6 +168,8 @@ public class VpnTest { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT; when(mContext.getApplicationInfo()).thenReturn(applicationInfo); + when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); doNothing().when(mNetService).registerObserver(any()); } @@ -544,23 +546,28 @@ public class VpnTest { final Network wifi = new Network(2); final Map<Network, NetworkCapabilities> networks = new HashMap<>(); - networks.put(mobile, new NetworkCapabilities() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NET_CAPABILITY_INTERNET) - .addCapability(NET_CAPABILITY_NOT_METERED) - .addCapability(NET_CAPABILITY_NOT_CONGESTED) - .setLinkDownstreamBandwidthKbps(10)); - networks.put(wifi, new NetworkCapabilities() - .addTransportType(TRANSPORT_WIFI) - .addCapability(NET_CAPABILITY_INTERNET) - .addCapability(NET_CAPABILITY_NOT_ROAMING) - .addCapability(NET_CAPABILITY_NOT_CONGESTED) - .setLinkUpstreamBandwidthKbps(20)); + networks.put( + mobile, + new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .setLinkDownstreamBandwidthKbps(10)); + networks.put( + wifi, + new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_METERED) + .addCapability(NET_CAPABILITY_NOT_ROAMING) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .setLinkUpstreamBandwidthKbps(20)); setMockedNetworks(networks); final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); + Vpn.updateCapabilities( + mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -570,17 +577,33 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); + Vpn.updateCapabilities( + mConnectivityManager, + new Network[] {mobile}, + caps, + false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); assertEquals(10, caps.getLinkDownstreamBandwidthKbps()); assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps()); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); + Vpn.updateCapabilities( + mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */); + assertTrue(caps.hasTransport(TRANSPORT_VPN)); + assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); + assertTrue(caps.hasTransport(TRANSPORT_WIFI)); + assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps()); + assertEquals(20, caps.getLinkUpstreamBandwidthKbps()); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + + Vpn.updateCapabilities( + mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -590,7 +613,11 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); + Vpn.updateCapabilities( + mConnectivityManager, + new Network[] {mobile, wifi}, + caps, + false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); |