summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt8
-rw-r--r--api/system-current.txt194
-rw-r--r--cmds/statsd/src/atoms.proto139
-rw-r--r--core/java/android/app/ActivityThread.java7
-rw-r--r--core/java/android/app/ContextImpl.java41
-rw-r--r--core/java/android/app/Notification.java4
-rw-r--r--core/java/android/net/VpnService.java21
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/util/FeatureFlagUtils.java3
-rw-r--r--core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java7
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java3
-rw-r--r--core/jni/android/graphics/Shader.cpp184
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/drawable/ic_media_seamless.xml25
-rw-r--r--core/res/res/layout/notification_template_material_big_media.xml4
-rw-r--r--core/res/res/values/dimens.xml2
-rw-r--r--core/res/res/values/strings.xml3
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--graphics/java/android/graphics/LinearGradient.java135
-rw-r--r--graphics/java/android/graphics/RadialGradient.java128
-rw-r--r--graphics/java/android/graphics/Shader.java66
-rw-r--r--graphics/java/android/graphics/SweepGradient.java113
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp4
-rw-r--r--media/java/android/media/session/ControllerCallbackLink.java2
-rw-r--r--media/java/android/media/session/ControllerLink.java2
-rw-r--r--media/java/android/media/session/MediaController.java1
-rw-r--r--media/java/android/media/session/MediaSession.java3
-rw-r--r--media/java/android/media/session/MediaSessionEngine.java2
-rw-r--r--media/java/android/media/session/SessionCallbackLink.java2
-rw-r--r--media/java/android/media/session/SessionLink.java2
-rw-r--r--native/webview/plat_support/draw_functor.cpp3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java114
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/Android.mk31
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml31
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/res/values/config.xml28
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml21
-rw-r--r--packages/overlays/FontArvoLatoOverlay/Android.mk31
-rw-r--r--packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml31
-rw-r--r--packages/overlays/FontArvoLatoOverlay/res/values/config.xml28
-rw-r--r--packages/overlays/FontArvoLatoOverlay/res/values/strings.xml21
-rw-r--r--packages/overlays/FontRubikRubikOverlay/Android.mk31
-rw-r--r--packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml31
-rw-r--r--packages/overlays/FontRubikRubikOverlay/res/values/config.xml28
-rw-r--r--packages/overlays/FontRubikRubikOverlay/res/values/strings.xml21
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java32
-rw-r--r--services/core/java/com/android/server/pm/OWNERS2
-rw-r--r--services/core/java/com/android/server/power/AttentionDetector.java19
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java30
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java25
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl6
-rw-r--r--telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl2
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java1
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java61
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));