diff options
108 files changed, 2967 insertions, 1206 deletions
diff --git a/api/current.txt b/api/current.txt index 143e3d87870b..afb456907b29 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3848,7 +3848,7 @@ package android.app { method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException; method public java.util.List<android.app.ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException; - method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; + method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException; method public deprecated boolean isInLockTaskMode(); method public boolean isLowRamDevice(); @@ -10940,12 +10940,13 @@ package android.content.pm { method public android.content.pm.VersionedPackage getDeclaringPackage(); method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages(); method public java.lang.String getName(); - method public int getVersion(); - method public boolean isBuiltin(); - method public boolean isDynamic(); - method public boolean isStatic(); + method public int getType(); + method public long getVersion(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR; + field public static final int TYPE_BUILTIN = 0; // 0x0 + field public static final int TYPE_DYNAMIC = 1; // 0x1 + field public static final int TYPE_STATIC = 2; // 0x2 field public static final int VERSION_UNDEFINED = -1; // 0xffffffff } @@ -12599,7 +12600,6 @@ package android.graphics { public class BitmapShader extends android.graphics.Shader { ctor public BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); - method public void set(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); } public class BlurMaskFilter extends android.graphics.MaskFilter { @@ -12852,8 +12852,6 @@ package android.graphics { ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix); ctor public ColorMatrixColorFilter(float[]); method public void getColorMatrix(android.graphics.ColorMatrix); - method public void setColorMatrix(android.graphics.ColorMatrix); - method public void setColorMatrixArray(float[]); } public abstract class ColorSpace { @@ -12994,8 +12992,6 @@ package android.graphics { public class ComposeShader extends android.graphics.Shader { ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode); ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.PorterDuff.Mode); - method public void set(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode); - method public void set(android.graphics.Shader, android.graphics.Shader, android.graphics.PorterDuff.Mode); } public class CornerPathEffect extends android.graphics.PathEffect { @@ -13068,15 +13064,11 @@ package android.graphics { ctor public LightingColorFilter(int, int); method public int getColorAdd(); method public int getColorMultiply(); - method public void setColorAdd(int); - method public void setColorMultiply(int); } public class LinearGradient extends android.graphics.Shader { ctor public LinearGradient(float, float, float, float, int[], float[], android.graphics.Shader.TileMode); ctor public LinearGradient(float, float, float, float, int, int, android.graphics.Shader.TileMode); - method public void set(float, float, float, float, int[], float[], android.graphics.Shader.TileMode); - method public void set(float, float, float, float, int, int, android.graphics.Shader.TileMode); } public class MaskFilter { @@ -13586,10 +13578,6 @@ package android.graphics { public class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); - method public int getColor(); - method public android.graphics.PorterDuff.Mode getMode(); - method public void setColor(int); - method public void setMode(android.graphics.PorterDuff.Mode); } public class PorterDuffXfermode extends android.graphics.Xfermode { @@ -13599,8 +13587,6 @@ package android.graphics { public class RadialGradient extends android.graphics.Shader { ctor public RadialGradient(float, float, float, int[], float[], android.graphics.Shader.TileMode); ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode); - method public void set(float, float, float, int[], float[], android.graphics.Shader.TileMode); - method public void set(float, float, float, int, int, android.graphics.Shader.TileMode); } public final class Rect implements android.os.Parcelable { @@ -13785,8 +13771,6 @@ package android.graphics { public class SweepGradient extends android.graphics.Shader { ctor public SweepGradient(float, float, int[], float[]); ctor public SweepGradient(float, float, int, int); - method public void set(float, float, int[], float[]); - method public void set(float, float, int, int); } public class Typeface { @@ -20800,13 +20784,10 @@ package android.location { method public boolean hasSpeedAccuracy(); method public boolean hasVerticalAccuracy(); method public boolean isFromMockProvider(); - method public void removeAccuracy(); - method public void removeAltitude(); - method public void removeBearing(); - method public void removeBearingAccuracy(); - method public void removeSpeed(); - method public void removeSpeedAccuracy(); - method public void removeVerticalAccuracy(); + method public deprecated void removeAccuracy(); + method public deprecated void removeAltitude(); + method public deprecated void removeBearing(); + method public deprecated void removeSpeed(); method public void reset(); method public void set(android.location.Location); method public void setAccuracy(float); @@ -22774,7 +22755,7 @@ package android.media { method public android.media.MediaPlayer.DrmInfo getDrmInfo(); method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException; method public int getDuration(); - method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; + method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; @@ -22788,7 +22769,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -22815,7 +22796,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); - method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); + method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -22856,6 +22837,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2 + field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 field public static final int SEEK_CLOSEST = 3; // 0x3 field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 field public static final int SEEK_NEXT_SYNC = 1; // 0x1 @@ -22865,7 +22850,6 @@ package android.media { } public static final class MediaPlayer.DrmInfo { - method public java.lang.String[] getMimes(); method public java.util.Map<java.util.UUID, byte[]> getPssh(); method public java.util.UUID[] getSupportedSchemes(); } @@ -22897,7 +22881,7 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract interface MediaPlayer.OnDrmConfigListener { + public static abstract interface MediaPlayer.OnDrmConfigHelper { method public abstract void onDrmConfig(android.media.MediaPlayer); } @@ -22906,7 +22890,7 @@ package android.media { } public static abstract interface MediaPlayer.OnDrmPreparedListener { - method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean); + method public abstract void onDrmPrepared(android.media.MediaPlayer, int); } public static abstract interface MediaPlayer.OnErrorListener { @@ -22937,8 +22921,12 @@ package android.media { method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int); } - public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException { - ctor public MediaPlayer.ProvisioningErrorException(java.lang.String); + public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String); + } + + public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String); } public static class MediaPlayer.TrackInfo implements android.os.Parcelable { @@ -25527,14 +25515,10 @@ package android.net { } public final class IpSecManager { - method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException; - method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException; method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; - method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform); - method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform); - method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform); + method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 @@ -25553,7 +25537,7 @@ package android.net { } public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { - method public void close(); + method public void close() throws java.io.IOException; method public int getPort(); method public java.io.FileDescriptor getSocket(); } @@ -26751,8 +26735,8 @@ package android.net.wifi.aware { } public class DiscoverySession { - method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); - method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); method public void destroy(); method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]); } @@ -26838,8 +26822,8 @@ package android.net.wifi.aware { } public class WifiAwareSession { - method public java.lang.String createNetworkSpecifierOpen(int, byte[]); - method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String); method public void destroy(); method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); @@ -37047,6 +37031,7 @@ package android.service.autofill { public abstract class AutofillService extends android.app.Service { ctor public AutofillService(); method public final deprecated void disableSelf(); + method public final android.service.autofill.FillEventHistory getFillEventHistory(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); @@ -37069,6 +37054,7 @@ package android.service.autofill { ctor public Dataset.Builder(); method public android.service.autofill.Dataset build(); method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender); + method public android.service.autofill.Dataset.Builder setId(java.lang.String); method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue); method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews); } @@ -37086,6 +37072,23 @@ package android.service.autofill { field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR; } + public final class FillEventHistory implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR; + } + + public static final class FillEventHistory.Event { + method public java.lang.String getDatasetId(); + method public int getType(); + field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2 + field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1 + field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 + field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 + } + public final class FillRequest implements android.os.Parcelable { method public int describeContents(); method public android.os.Bundle getClientState(); @@ -37110,6 +37113,7 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews); method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle); method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle); + method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...); method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo); } @@ -37122,6 +37126,7 @@ package android.service.autofill { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR; + field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1 field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2 field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 4; // 0x4 field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 16; // 0x10 @@ -37134,9 +37139,9 @@ package android.service.autofill { ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]); method public android.service.autofill.SaveInfo build(); method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); + method public android.service.autofill.SaveInfo.Builder setFlags(int); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); - method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); } public final class SaveRequest implements android.os.Parcelable { @@ -45938,7 +45943,9 @@ package android.view { field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1 field public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0; // 0x0 field public static final int IMPORTANT_FOR_AUTOFILL_NO = 2; // 0x2 + field public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 8; // 0x8 field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1 + field public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 4; // 0x4 field public static final int INVISIBLE = 4; // 0x4 field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000 field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2 diff --git a/api/removed.txt b/api/removed.txt index 0f5b81abad4c..b6c2a98c1c68 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -63,6 +63,12 @@ package android.content.pm { field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1 } + public final class SharedLibraryInfo implements android.os.Parcelable { + method public boolean isBuiltin(); + method public boolean isDynamic(); + method public boolean isStatic(); + } + } package android.database { @@ -126,6 +132,16 @@ package android.hardware { } +package android.location { + + public class Location implements android.os.Parcelable { + method public deprecated void removeBearingAccuracy(); + method public deprecated void removeSpeedAccuracy(); + method public deprecated void removeVerticalAccuracy(); + } + +} + package android.media { public final class AudioFormat implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index e0148092c3b3..84b9da98f526 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3989,7 +3989,7 @@ package android.app { method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException; method public java.util.List<android.app.ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException; - method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; + method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException; method public int getUidImportance(int); method public deprecated boolean isInLockTaskMode(); @@ -11700,12 +11700,13 @@ package android.content.pm { method public android.content.pm.VersionedPackage getDeclaringPackage(); method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages(); method public java.lang.String getName(); - method public int getVersion(); - method public boolean isBuiltin(); - method public boolean isDynamic(); - method public boolean isStatic(); + method public int getType(); + method public long getVersion(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR; + field public static final int TYPE_BUILTIN = 0; // 0x0 + field public static final int TYPE_DYNAMIC = 1; // 0x1 + field public static final int TYPE_STATIC = 2; // 0x2 field public static final int VERSION_UNDEFINED = -1; // 0xffffffff } @@ -13373,7 +13374,6 @@ package android.graphics { public class BitmapShader extends android.graphics.Shader { ctor public BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); - method public void set(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); } public class BlurMaskFilter extends android.graphics.MaskFilter { @@ -13626,8 +13626,6 @@ package android.graphics { ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix); ctor public ColorMatrixColorFilter(float[]); method public void getColorMatrix(android.graphics.ColorMatrix); - method public void setColorMatrix(android.graphics.ColorMatrix); - method public void setColorMatrixArray(float[]); } public abstract class ColorSpace { @@ -13768,8 +13766,6 @@ package android.graphics { public class ComposeShader extends android.graphics.Shader { ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode); ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.PorterDuff.Mode); - method public void set(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode); - method public void set(android.graphics.Shader, android.graphics.Shader, android.graphics.PorterDuff.Mode); } public class CornerPathEffect extends android.graphics.PathEffect { @@ -13842,15 +13838,11 @@ package android.graphics { ctor public LightingColorFilter(int, int); method public int getColorAdd(); method public int getColorMultiply(); - method public void setColorAdd(int); - method public void setColorMultiply(int); } public class LinearGradient extends android.graphics.Shader { ctor public LinearGradient(float, float, float, float, int[], float[], android.graphics.Shader.TileMode); ctor public LinearGradient(float, float, float, float, int, int, android.graphics.Shader.TileMode); - method public void set(float, float, float, float, int[], float[], android.graphics.Shader.TileMode); - method public void set(float, float, float, float, int, int, android.graphics.Shader.TileMode); } public class MaskFilter { @@ -14360,10 +14352,6 @@ package android.graphics { public class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); - method public int getColor(); - method public android.graphics.PorterDuff.Mode getMode(); - method public void setColor(int); - method public void setMode(android.graphics.PorterDuff.Mode); } public class PorterDuffXfermode extends android.graphics.Xfermode { @@ -14373,8 +14361,6 @@ package android.graphics { public class RadialGradient extends android.graphics.Shader { ctor public RadialGradient(float, float, float, int[], float[], android.graphics.Shader.TileMode); ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode); - method public void set(float, float, float, int[], float[], android.graphics.Shader.TileMode); - method public void set(float, float, float, int, int, android.graphics.Shader.TileMode); } public final class Rect implements android.os.Parcelable { @@ -14559,8 +14545,6 @@ package android.graphics { public class SweepGradient extends android.graphics.Shader { ctor public SweepGradient(float, float, int[], float[]); ctor public SweepGradient(float, float, int, int); - method public void set(float, float, int[], float[]); - method public void set(float, float, int, int); } public class Typeface { @@ -22534,13 +22518,10 @@ package android.location { method public boolean isComplete(); method public boolean isFromMockProvider(); method public void makeComplete(); - method public void removeAccuracy(); - method public void removeAltitude(); - method public void removeBearing(); - method public void removeBearingAccuracy(); - method public void removeSpeed(); - method public void removeSpeedAccuracy(); - method public void removeVerticalAccuracy(); + method public deprecated void removeAccuracy(); + method public deprecated void removeAltitude(); + method public deprecated void removeBearing(); + method public deprecated void removeSpeed(); method public void reset(); method public void set(android.location.Location); method public void setAccuracy(float); @@ -24610,7 +24591,7 @@ package android.media { method public android.media.MediaPlayer.DrmInfo getDrmInfo(); method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException; method public int getDuration(); - method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; + method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; @@ -24624,7 +24605,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -24651,7 +24632,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); - method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); + method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -24692,6 +24673,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2 + field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 field public static final int SEEK_CLOSEST = 3; // 0x3 field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 field public static final int SEEK_NEXT_SYNC = 1; // 0x1 @@ -24701,7 +24686,6 @@ package android.media { } public static final class MediaPlayer.DrmInfo { - method public java.lang.String[] getMimes(); method public java.util.Map<java.util.UUID, byte[]> getPssh(); method public java.util.UUID[] getSupportedSchemes(); } @@ -24733,7 +24717,7 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract interface MediaPlayer.OnDrmConfigListener { + public static abstract interface MediaPlayer.OnDrmConfigHelper { method public abstract void onDrmConfig(android.media.MediaPlayer); } @@ -24742,7 +24726,7 @@ package android.media { } public static abstract interface MediaPlayer.OnDrmPreparedListener { - method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean); + method public abstract void onDrmPrepared(android.media.MediaPlayer, int); } public static abstract interface MediaPlayer.OnErrorListener { @@ -24773,8 +24757,12 @@ package android.media { method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int); } - public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException { - ctor public MediaPlayer.ProvisioningErrorException(java.lang.String); + public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String); + } + + public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String); } public static class MediaPlayer.TrackInfo implements android.os.Parcelable { @@ -27716,14 +27704,10 @@ package android.net { } public final class IpSecManager { - method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException; - method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException; method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; - method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform); - method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform); - method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform); + method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 @@ -27742,7 +27726,7 @@ package android.net { } public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { - method public void close(); + method public void close() throws java.io.IOException; method public int getPort(); method public java.io.FileDescriptor getSocket(); } @@ -29494,9 +29478,9 @@ package android.net.wifi.aware { } public class DiscoverySession { - method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); - method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); - method public java.lang.String createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]); method public void destroy(); method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]); } @@ -29582,9 +29566,9 @@ package android.net.wifi.aware { } public class WifiAwareSession { - method public java.lang.String createNetworkSpecifierOpen(int, byte[]); - method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); - method public java.lang.String createNetworkSpecifierPmk(int, byte[], byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, byte[], byte[]); method public void destroy(); method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); @@ -40159,6 +40143,7 @@ package android.service.autofill { public abstract class AutofillService extends android.app.Service { ctor public AutofillService(); method public final deprecated void disableSelf(); + method public final android.service.autofill.FillEventHistory getFillEventHistory(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); @@ -40181,6 +40166,7 @@ package android.service.autofill { ctor public Dataset.Builder(); method public android.service.autofill.Dataset build(); method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender); + method public android.service.autofill.Dataset.Builder setId(java.lang.String); method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue); method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews); } @@ -40198,6 +40184,23 @@ package android.service.autofill { field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR; } + public final class FillEventHistory implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR; + } + + public static final class FillEventHistory.Event { + method public java.lang.String getDatasetId(); + method public int getType(); + field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2 + field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1 + field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 + field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 + } + public final class FillRequest implements android.os.Parcelable { method public int describeContents(); method public android.os.Bundle getClientState(); @@ -40222,6 +40225,7 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews); method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle); method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle); + method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...); method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo); } @@ -40234,6 +40238,7 @@ package android.service.autofill { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR; + field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1 field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2 field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 4; // 0x4 field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 16; // 0x10 @@ -40246,9 +40251,9 @@ package android.service.autofill { ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]); method public android.service.autofill.SaveInfo build(); method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); + method public android.service.autofill.SaveInfo.Builder setFlags(int); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); - method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); } public final class SaveRequest implements android.os.Parcelable { @@ -49513,7 +49518,9 @@ package android.view { field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1 field public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0; // 0x0 field public static final int IMPORTANT_FOR_AUTOFILL_NO = 2; // 0x2 + field public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 8; // 0x8 field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1 + field public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 4; // 0x4 field public static final int INVISIBLE = 4; // 0x4 field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000 field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2 diff --git a/api/system-removed.txt b/api/system-removed.txt index 823d88faaece..6d82a49b30e0 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -61,6 +61,12 @@ package android.content.pm { field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1 } + public final class SharedLibraryInfo implements android.os.Parcelable { + method public boolean isBuiltin(); + method public boolean isDynamic(); + method public boolean isStatic(); + } + } package android.database { @@ -124,6 +130,16 @@ package android.hardware { } +package android.location { + + public class Location implements android.os.Parcelable { + method public deprecated void removeBearingAccuracy(); + method public deprecated void removeSpeedAccuracy(); + method public deprecated void removeVerticalAccuracy(); + } + +} + package android.media { public final class AudioFormat implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index 543fcc60fb11..0ca882a11795 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3852,7 +3852,7 @@ package android.app { method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException; method public java.util.List<android.app.ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException; - method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; + method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException; method public int getUidImportance(int); method public deprecated boolean isInLockTaskMode(); @@ -10981,12 +10981,13 @@ package android.content.pm { method public android.content.pm.VersionedPackage getDeclaringPackage(); method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages(); method public java.lang.String getName(); - method public int getVersion(); - method public boolean isBuiltin(); - method public boolean isDynamic(); - method public boolean isStatic(); + method public int getType(); + method public long getVersion(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR; + field public static final int TYPE_BUILTIN = 0; // 0x0 + field public static final int TYPE_DYNAMIC = 1; // 0x1 + field public static final int TYPE_STATIC = 2; // 0x2 field public static final int VERSION_UNDEFINED = -1; // 0xffffffff } @@ -12641,7 +12642,6 @@ package android.graphics { public class BitmapShader extends android.graphics.Shader { ctor public BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); - method public void set(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); } public class BlurMaskFilter extends android.graphics.MaskFilter { @@ -12894,8 +12894,6 @@ package android.graphics { ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix); ctor public ColorMatrixColorFilter(float[]); method public void getColorMatrix(android.graphics.ColorMatrix); - method public void setColorMatrix(android.graphics.ColorMatrix); - method public void setColorMatrixArray(float[]); } public abstract class ColorSpace { @@ -13036,8 +13034,6 @@ package android.graphics { public class ComposeShader extends android.graphics.Shader { ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode); ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.PorterDuff.Mode); - method public void set(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode); - method public void set(android.graphics.Shader, android.graphics.Shader, android.graphics.PorterDuff.Mode); } public class CornerPathEffect extends android.graphics.PathEffect { @@ -13110,15 +13106,11 @@ package android.graphics { ctor public LightingColorFilter(int, int); method public int getColorAdd(); method public int getColorMultiply(); - method public void setColorAdd(int); - method public void setColorMultiply(int); } public class LinearGradient extends android.graphics.Shader { ctor public LinearGradient(float, float, float, float, int[], float[], android.graphics.Shader.TileMode); ctor public LinearGradient(float, float, float, float, int, int, android.graphics.Shader.TileMode); - method public void set(float, float, float, float, int[], float[], android.graphics.Shader.TileMode); - method public void set(float, float, float, float, int, int, android.graphics.Shader.TileMode); } public class MaskFilter { @@ -13628,10 +13620,6 @@ package android.graphics { public class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); - method public int getColor(); - method public android.graphics.PorterDuff.Mode getMode(); - method public void setColor(int); - method public void setMode(android.graphics.PorterDuff.Mode); } public class PorterDuffXfermode extends android.graphics.Xfermode { @@ -13641,8 +13629,6 @@ package android.graphics { public class RadialGradient extends android.graphics.Shader { ctor public RadialGradient(float, float, float, int[], float[], android.graphics.Shader.TileMode); ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode); - method public void set(float, float, float, int[], float[], android.graphics.Shader.TileMode); - method public void set(float, float, float, int, int, android.graphics.Shader.TileMode); } public final class Rect implements android.os.Parcelable { @@ -13827,8 +13813,6 @@ package android.graphics { public class SweepGradient extends android.graphics.Shader { ctor public SweepGradient(float, float, int[], float[]); ctor public SweepGradient(float, float, int, int); - method public void set(float, float, int[], float[]); - method public void set(float, float, int, int); } public class Typeface { @@ -20906,13 +20890,10 @@ package android.location { method public boolean hasSpeedAccuracy(); method public boolean hasVerticalAccuracy(); method public boolean isFromMockProvider(); - method public void removeAccuracy(); - method public void removeAltitude(); - method public void removeBearing(); - method public void removeBearingAccuracy(); - method public void removeSpeed(); - method public void removeSpeedAccuracy(); - method public void removeVerticalAccuracy(); + method public deprecated void removeAccuracy(); + method public deprecated void removeAltitude(); + method public deprecated void removeBearing(); + method public deprecated void removeSpeed(); method public void reset(); method public void set(android.location.Location); method public void setAccuracy(float); @@ -22881,7 +22862,7 @@ package android.media { method public android.media.MediaPlayer.DrmInfo getDrmInfo(); method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException; method public int getDuration(); - method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; + method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; @@ -22895,7 +22876,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -22922,7 +22903,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); - method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); + method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -22963,6 +22944,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2 + field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 field public static final int SEEK_CLOSEST = 3; // 0x3 field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 field public static final int SEEK_NEXT_SYNC = 1; // 0x1 @@ -22972,7 +22957,6 @@ package android.media { } public static final class MediaPlayer.DrmInfo { - method public java.lang.String[] getMimes(); method public java.util.Map<java.util.UUID, byte[]> getPssh(); method public java.util.UUID[] getSupportedSchemes(); } @@ -23004,7 +22988,7 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract interface MediaPlayer.OnDrmConfigListener { + public static abstract interface MediaPlayer.OnDrmConfigHelper { method public abstract void onDrmConfig(android.media.MediaPlayer); } @@ -23013,7 +22997,7 @@ package android.media { } public static abstract interface MediaPlayer.OnDrmPreparedListener { - method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean); + method public abstract void onDrmPrepared(android.media.MediaPlayer, int); } public static abstract interface MediaPlayer.OnErrorListener { @@ -23044,8 +23028,12 @@ package android.media { method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int); } - public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException { - ctor public MediaPlayer.ProvisioningErrorException(java.lang.String); + public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String); + } + + public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String); } public static class MediaPlayer.TrackInfo implements android.os.Parcelable { @@ -25634,14 +25622,10 @@ package android.net { } public final class IpSecManager { - method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException; - method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException; method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; - method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform); - method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform); - method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform); + method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 @@ -25660,7 +25644,7 @@ package android.net { } public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { - method public void close(); + method public void close() throws java.io.IOException; method public int getPort(); method public java.io.FileDescriptor getSocket(); } @@ -26858,8 +26842,8 @@ package android.net.wifi.aware { } public class DiscoverySession { - method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); - method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); method public void destroy(); method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]); } @@ -26945,8 +26929,8 @@ package android.net.wifi.aware { } public class WifiAwareSession { - method public java.lang.String createNetworkSpecifierOpen(int, byte[]); - method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String); method public void destroy(); method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); @@ -37200,6 +37184,7 @@ package android.service.autofill { public abstract class AutofillService extends android.app.Service { ctor public AutofillService(); method public final deprecated void disableSelf(); + method public final android.service.autofill.FillEventHistory getFillEventHistory(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); @@ -37222,6 +37207,7 @@ package android.service.autofill { ctor public Dataset.Builder(); method public android.service.autofill.Dataset build(); method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender); + method public android.service.autofill.Dataset.Builder setId(java.lang.String); method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue); method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews); } @@ -37239,6 +37225,23 @@ package android.service.autofill { field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR; } + public final class FillEventHistory implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR; + } + + public static final class FillEventHistory.Event { + method public java.lang.String getDatasetId(); + method public int getType(); + field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2 + field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1 + field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 + field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 + } + public final class FillRequest implements android.os.Parcelable { method public int describeContents(); method public android.os.Bundle getClientState(); @@ -37263,6 +37266,7 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews); method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle); method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle); + method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...); method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo); } @@ -37275,6 +37279,7 @@ package android.service.autofill { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR; + field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1 field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2 field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 4; // 0x4 field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 16; // 0x10 @@ -37287,9 +37292,9 @@ package android.service.autofill { ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]); method public android.service.autofill.SaveInfo build(); method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); + method public android.service.autofill.SaveInfo.Builder setFlags(int); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); - method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); } public final class SaveRequest implements android.os.Parcelable { @@ -46308,7 +46313,9 @@ package android.view { field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1 field public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0; // 0x0 field public static final int IMPORTANT_FOR_AUTOFILL_NO = 2; // 0x2 + field public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 8; // 0x8 field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1 + field public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 4; // 0x4 field public static final int INVISIBLE = 4; // 0x4 field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000 field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2 diff --git a/api/test-removed.txt b/api/test-removed.txt index 0f5b81abad4c..b6c2a98c1c68 100644 --- a/api/test-removed.txt +++ b/api/test-removed.txt @@ -63,6 +63,12 @@ package android.content.pm { field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1 } + public final class SharedLibraryInfo implements android.os.Parcelable { + method public boolean isBuiltin(); + method public boolean isDynamic(); + method public boolean isStatic(); + } + } package android.database { @@ -126,6 +132,16 @@ package android.hardware { } +package android.location { + + public class Location implements android.os.Parcelable { + method public deprecated void removeBearingAccuracy(); + method public deprecated void removeSpeedAccuracy(); + method public deprecated void removeVerticalAccuracy(); + } + +} + package android.media { public final class AudioFormat implements android.os.Parcelable { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 66167a3c986a..a4dcf630bc3e 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2564,6 +2564,10 @@ public class ActivityManager { * <p><b>Note: this method is only intended for debugging or implementing * service management type user interfaces.</b></p> * + * @deprecated As of {@link android.os.Build.VERSION_CODES#O}, this method + * is no longer available to third party applications. For backwards compatibility, + * it will still return the caller's own services. + * * @param maxNum The maximum number of entries to return in the list. The * actual number returned may be smaller, depending on how many services * are running. @@ -2571,6 +2575,7 @@ public class ActivityManager { * @return Returns a list of RunningServiceInfo records describing each of * the running tasks. */ + @Deprecated public List<RunningServiceInfo> getRunningServices(int maxNum) throws SecurityException { try { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index e07b7e4a03a1..027ddf51a069 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -79,6 +79,8 @@ import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.provider.Settings; import android.util.ArrayMap; +import android.util.IconDrawableFactory; +import android.util.LauncherIcons; import android.util.Log; import android.view.Display; @@ -1245,16 +1247,9 @@ public class ApplicationPackageManager extends PackageManager { if (!isManagedProfile(user.getIdentifier())) { return icon; } - Drawable badgeShadow = getDrawable("system", - com.android.internal.R.drawable.ic_corp_icon_badge_shadow, null); - Drawable badgeColor = getDrawable("system", - com.android.internal.R.drawable.ic_corp_icon_badge_color, null); - badgeColor.setTint(getUserBadgeColor(user)); - Drawable badgeForeground = getDrawable("system", - com.android.internal.R.drawable.ic_corp_icon_badge_case, null); - - Drawable badge = new LayerDrawable( - new Drawable[] {badgeShadow, badgeColor, badgeForeground }); + Drawable badge = new LauncherIcons(mContext).getBadgeDrawable( + com.android.internal.R.drawable.ic_corp_icon_badge_case, + getUserBadgeColor(user)); return getBadgedDrawable(icon, badge, null, true); } @@ -1268,14 +1263,6 @@ public class ApplicationPackageManager extends PackageManager { return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true); } - // Should have enough colors to cope with UserManagerService.getMaxManagedProfiles() - @VisibleForTesting - public static final int[] CORP_BADGE_COLORS = new int[] { - com.android.internal.R.color.profile_badge_1, - com.android.internal.R.color.profile_badge_2, - com.android.internal.R.color.profile_badge_3 - }; - @VisibleForTesting public static final int[] CORP_BADGE_LABEL_RES_ID = new int[] { com.android.internal.R.string.managed_profile_label_badge, @@ -1284,12 +1271,7 @@ public class ApplicationPackageManager extends PackageManager { }; private int getUserBadgeColor(UserHandle user) { - int badge = getUserManager().getManagedProfileBadge(user.getIdentifier()); - if (badge < 0) { - badge = 0; - } - int resourceId = CORP_BADGE_COLORS[badge % CORP_BADGE_COLORS.length]; - return Resources.getSystem().getColor(resourceId, null); + return IconDrawableFactory.getUserBadgeColor(getUserManager(), user.getIdentifier()); } @Override diff --git a/core/java/android/content/pm/ChangedPackages.java b/core/java/android/content/pm/ChangedPackages.java index 94b8a5dfd5e0..78c057d9e0f4 100644 --- a/core/java/android/content/pm/ChangedPackages.java +++ b/core/java/android/content/pm/ChangedPackages.java @@ -17,6 +17,7 @@ package android.content.pm; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.content.Intent; import android.os.Parcel; import android.os.Parcelable; @@ -26,6 +27,7 @@ import java.util.List; /** * Packages that have been changed since the last time they * were requested. + * @see PackageManager#getChangedPackages(int) */ public final class ChangedPackages implements Parcelable { /** The last known sequence number for these changes */ @@ -33,6 +35,7 @@ public final class ChangedPackages implements Parcelable { /** The names of the packages that have changed */ private final List<String> mPackageNames; + @TestApi public ChangedPackages(int sequenceNumber, @NonNull List<String> packageNames) { this.mSequenceNumber = sequenceNumber; this.mPackageNames = packageNames; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 09906be7cd26..178b9671fc27 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -54,6 +54,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import android.provider.Settings; import android.util.AndroidException; import android.util.Log; @@ -3983,6 +3984,8 @@ public abstract class PackageManager { * <p>If no packages have been changed, returns <code>null</code>. * <p>The sequence number starts at <code>0</code> and is * reset every boot. + * @param sequenceNumber The first sequence number for which to retrieve package changes. + * @see Settings.Global#BOOT_COUNT */ public abstract @Nullable ChangedPackages getChangedPackages( @IntRange(from=0) int sequenceNumber); @@ -6256,18 +6259,18 @@ public abstract class PackageManager { /** * Checks whether the calling package is allowed to request package installs through package - * installer. Apps are encouraged to call this api before launching the package installer via + * installer. Apps are encouraged to call this API before launching the package installer via * intent {@link android.content.Intent#ACTION_INSTALL_PACKAGE}. Starting from Android O, the * user can explicitly choose what external sources they trust to install apps on the device. - * If this api returns false, the install request will be blocked by the package installer and + * If this API returns false, the install request will be blocked by the package installer and * a dialog will be shown to the user with an option to launch settings to change their * preference. An application must target Android O or higher and declare permission - * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES} in order to use this api. + * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES} in order to use this API. * * @return true if the calling package is trusted by the user to request install packages on * the device, false otherwise. - * @see {@link android.content.Intent#ACTION_INSTALL_PACKAGE} - * @see {@link android.provider.Settings#ACTION_MANAGE_UNKNOWN_APP_SOURCES} + * @see android.content.Intent#ACTION_INSTALL_PACKAGE + * @see android.provider.Settings#ACTION_MANAGE_UNKNOWN_APP_SOURCES */ public abstract boolean canRequestPackageInstalls(); diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index d79deb2b8459..0ad4874d41fe 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -16,11 +16,14 @@ package android.content.pm; +import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.List; @@ -31,28 +34,37 @@ import java.util.List; * static - updatable non backwards-compatible emulating static linking. */ public final class SharedLibraryInfo implements Parcelable { + + /** @hide */ + @IntDef( + flag = true, + value = { + TYPE_BUILTIN, + TYPE_DYNAMIC, + TYPE_STATIC, + }) + @Retention(RetentionPolicy.SOURCE) + @interface Type{} + /** * Shared library type: this library is a part of the OS * and cannot be updated or uninstalled. - * @hide */ - public static final int TYPE_BUILTIN = 0x1<<0; + public static final int TYPE_BUILTIN = 0; /** * Shared library type: this library is backwards-compatible, can * be updated, and updates can be uninstalled. Clients link against * the latest version of the library. - * @hide */ - public static final int TYPE_DYNAMIC = 0x1<<1; + public static final int TYPE_DYNAMIC = 1; /** * Shared library type: this library is <strong>not</strong> backwards * -compatible, can be updated and updates can be uninstalled. Clients * link against a specific version of the library. - * @hide */ - public static final int TYPE_STATIC = 0x1<<2; + public static final int TYPE_STATIC = 2; /** * Constant for referring to an undefined version. @@ -60,8 +72,10 @@ public final class SharedLibraryInfo implements Parcelable { public static final int VERSION_UNDEFINED = -1; private final String mName; + + // TODO: Make long when we change the paltform to use longs private final int mVersion; - private final int mType; + private final @Type int mType; private final VersionedPackage mDeclaringPackage; private final List<VersionedPackage> mDependentPackages; @@ -90,13 +104,18 @@ public final class SharedLibraryInfo implements Parcelable { parcel.readParcelable(null), parcel.readArrayList(null)); } - /** @hide */ - public int getType() { + /** + * Gets the type of this library. + * + * @return The library type. + */ + public @Type int getType() { return mType; } /** - * Gets the library name. + * Gets the library name an app defines in its manifest + * to depend on the library. * * @return The name. */ @@ -105,40 +124,36 @@ public final class SharedLibraryInfo implements Parcelable { } /** - * Gets the version of the library. For {@link #isStatic()} static} libraries - * this is the declared version and for {@link #isDynamic()} dynamic} and - * {@link #isBuiltin()} builtin} it is {@link #VERSION_UNDEFINED} as these + * Gets the version of the library. For {@link #TYPE_STATIC static} libraries + * this is the declared version and for {@link #TYPE_DYNAMIC dynamic} and + * {@link #TYPE_BUILTIN builtin} it is {@link #VERSION_UNDEFINED} as these * are not versioned. * * @return The version. */ - public @IntRange(from = -1) int getVersion() { + public @IntRange(from = -1) long getVersion() { return mVersion; } /** - * @return whether this library is builtin which means that it - * is a part of the OS and cannot be updated or uninstalled. + * @hide + * @removed */ public boolean isBuiltin() { return mType == TYPE_BUILTIN; } /** - * @return whether this library is dynamic which means that it - * is backwards-compatible, can be updated, and updates can be - * uninstalled. Clients link against the latest version of the - * library. + * @hide + * @removed */ public boolean isDynamic() { return mType == TYPE_DYNAMIC; } /** - * @return whether this library is dynamic which means that it - * is <strong>not</strong> backwards-compatible, can be updated - * and updates can be uninstalled. Clients link against a specific - * version of the library. + * @hide + * @removed */ public boolean isStatic() { return mType == TYPE_STATIC; diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java index 04482210c088..3c6baa76558a 100644 --- a/core/java/android/metrics/LogMaker.java +++ b/core/java/android/metrics/LogMaker.java @@ -54,7 +54,11 @@ public class LogMaker { /* Deserialize from the eventlog */ public LogMaker(Object[] items) { - deserialize(items); + if (items != null) { + deserialize(items); + } else { + setCategory(MetricsEvent.VIEW_UNKNOWN); + } } /** @param category to replace the existing setting. */ @@ -94,6 +98,16 @@ public class LogMaker { } /** + * Set event latency. + * + * @hide // TODO Expose in the future? Too late for O. + */ + public LogMaker setLatency(long milliseconds) { + entries.put(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, milliseconds); + return this; + } + + /** * This will be set by the system when the log is persisted. * Client-supplied values will be ignored. * @@ -363,13 +377,13 @@ public class LogMaker { */ public void deserialize(Object[] items) { int i = 0; - while (i < items.length) { + while (items != null && i < items.length) { Object key = items[i++]; Object value = i < items.length ? items[i++] : null; if (key instanceof Integer) { entries.put((Integer) key, value); } else { - Log.i(TAG, "Invalid key " + key.toString()); + Log.i(TAG, "Invalid key " + (key == null ? "null" : key.toString())); } } } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index f8702e2e00e7..375b7eeb013a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -245,6 +245,7 @@ public final class IpSecManager { * * @param socket a stream socket * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + * @hide */ public void applyTransportModeTransform(Socket socket, IpSecTransform transform) throws IOException { @@ -262,6 +263,7 @@ public final class IpSecManager { * * @param socket a datagram socket * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + * @hide */ public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) throws IOException { @@ -284,7 +286,7 @@ public final class IpSecManager { * address associated with that transform will throw an IOException. In addition, if the * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to * send() or receive() until the transform is removed from the socket by calling {@link - * #removeTransportModeTransform(Socket, IpSecTransform)}; + * #removeTransportModeTransform(FileDescriptor, IpSecTransform)}; * * @param socket a socket file descriptor * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. @@ -316,8 +318,10 @@ public final class IpSecManager { * * @param socket a socket that previously had a transform applied to it. * @param transform the IPsec Transform that was previously applied to the given socket + * @hide */ - public void removeTransportModeTransform(Socket socket, IpSecTransform transform) { + public void removeTransportModeTransform(Socket socket, IpSecTransform transform) + throws IOException { removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform); } @@ -330,8 +334,10 @@ public final class IpSecManager { * * @param socket a socket that previously had a transform applied to it. * @param transform the IPsec Transform that was previously applied to the given socket + * @hide */ - public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) { + public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) + throws IOException { removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); } @@ -345,7 +351,8 @@ public final class IpSecManager { * @param socket a socket file descriptor that previously had a transform applied to it. * @param transform the IPsec Transform that was previously applied to the given socket */ - public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) { + public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + throws IOException { removeTransportModeTransform(new ParcelFileDescriptor(socket), transform); } @@ -419,7 +426,7 @@ public final class IpSecManager { * * @param fd a file descriptor previously returned as a UDP Encapsulation socket. */ - public void close() { + public void close() throws IOException { // TODO: Go close the socket mCloseGuard.close(); } diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index d3adce73582e..7496cb28f046 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -135,6 +135,7 @@ public class Preference implements Comparable<Preference> { private boolean mDependencyMet = true; private boolean mParentDependencyMet = true; private boolean mRecycleEnabled = true; + private boolean mHasSingleLineTitleAttr; private boolean mSingleLineTitle = true; private boolean mIconSpaceReserved; @@ -303,6 +304,7 @@ public class Preference implements Comparable<Preference> { case com.android.internal.R.styleable.Preference_singleLineTitle: mSingleLineTitle = a.getBoolean(attr, mSingleLineTitle); + mHasSingleLineTitleAttr = true; break; case com.android.internal.R.styleable.Preference_iconSpaceReserved: @@ -609,7 +611,9 @@ public class Preference implements Comparable<Preference> { if (!TextUtils.isEmpty(title)) { titleView.setText(title); titleView.setVisibility(View.VISIBLE); - titleView.setSingleLine(mSingleLineTitle); + if (mHasSingleLineTitleAttr) { + titleView.setSingleLine(mSingleLineTitle); + } } else { titleView.setVisibility(View.GONE); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c6ea9586374d..f32f163a86b0 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7077,6 +7077,7 @@ public final class Settings { CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED); CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION); CLONE_TO_MANAGED_PROFILE.add(ALLOWED_GEOLOCATION_ORIGINS); + CLONE_TO_MANAGED_PROFILE.add(AUTOFILL_SERVICE); CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD); CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES); CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS); diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index 5e49b8f0553f..813c54f53db9 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -247,7 +247,7 @@ public abstract class AutofillService extends Service { * @param callback object used to notify the result of the request. */ public void onSaveRequest(@NonNull SaveRequest request, @NonNull SaveCallback callback) { - List<FillContext> contexts = request.getFillContexts(); + final List<FillContext> contexts = request.getFillContexts(); onSaveRequest(contexts.get(contexts.size() - 1).getStructure(), request.getClientState(), callback); } @@ -285,4 +285,22 @@ public abstract class AutofillService extends Service { // TODO(b/33197203): Remove when GCore has migrated off this API getSystemService(AutofillManager.class).disableOwnedAutofillServices(); } + + /** + * Returns the {@link FillEventHistory.Event events} since the last {@link FillResponse} was + * returned. + * + * <p>The history is not persisted over reboots. + * + * @return The history or {@code null} if there are not events. + */ + @Nullable public final FillEventHistory getFillEventHistory() { + AutofillManager afm = getSystemService(AutofillManager.class); + + if (afm == null) { + return null; + } else { + return afm.getFillEventHistory(); + } + } } diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index e77bd0d753ac..e04fae7bc2b5 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -24,6 +24,7 @@ import android.content.IntentSender; import android.os.Parcel; import android.os.Parcelable; import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.widget.RemoteViews; import com.android.internal.util.Preconditions; @@ -50,6 +51,7 @@ public final class Dataset implements Parcelable { private final ArrayList<RemoteViews> mFieldPresentations; private final RemoteViews mPresentation; private final IntentSender mAuthentication; + @Nullable String mId; private Dataset(Builder builder) { mFieldIds = builder.mFieldIds; @@ -57,6 +59,7 @@ public final class Dataset implements Parcelable { mFieldPresentations = builder.mFieldPresentations; mPresentation = builder.mPresentation; mAuthentication = builder.mAuthentication; + mId = builder.mId; } /** @hide */ @@ -89,7 +92,7 @@ public final class Dataset implements Parcelable { public String toString() { if (!DEBUG) return super.toString(); - return new StringBuilder("Dataset [") + return new StringBuilder("Dataset " + mId + " [") .append("fieldIds=").append(mFieldIds) .append(", fieldValues=").append(mFieldValues) .append(", fieldPresentations=") @@ -100,6 +103,17 @@ public final class Dataset implements Parcelable { } /** + * Gets the id of this dataset. + * + * @return The id of this dataset or {@code null} if not set + * + * @hide + */ + public String getId() { + return mId; + } + + /** * A builder for {@link Dataset} objects. You must to provide at least * one value for a field or set an authentication intent. */ @@ -110,6 +124,7 @@ public final class Dataset implements Parcelable { private RemoteViews mPresentation; private IntentSender mAuthentication; private boolean mDestroyed; + @Nullable private String mId; /** * Creates a new builder. @@ -173,6 +188,25 @@ public final class Dataset implements Parcelable { } /** + * Sets the id for the dataset. + * + * <p>The id of the last selected dataset can be read from + * {@link AutofillService#getFillEventHistory()}. If the id is not set it will not be clear + * if a dataset was selected as {@link AutofillService#getFillEventHistory()} uses + * {@code null} to indicate that no dataset was selected. + * + * @param id id for this dataset or {@code null} to unset. + + * @return This builder. + */ + public @NonNull Builder setId(@Nullable String id) { + throwIfDestroyed(); + + mId = id; + return this; + } + + /** * Sets the value of a field. * * @param id id returned by {@link @@ -269,6 +303,7 @@ public final class Dataset implements Parcelable { parcel.writeTypedArrayList(mFieldValues, flags); parcel.writeParcelableList(mFieldPresentations, flags); parcel.writeParcelable(mAuthentication, flags); + parcel.writeString(mId); } public static final Creator<Dataset> CREATOR = new Creator<Dataset>() { @@ -295,6 +330,7 @@ public final class Dataset implements Parcelable { builder.setValueAndPresentation(id, value, fieldPresentation); } builder.setAuthentication(parcel.readParcelable(null)); + builder.setId(parcel.readString()); return builder.build(); } diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java index a009be805ce7..7774bdd4c410 100644 --- a/core/java/android/service/autofill/FillCallback.java +++ b/core/java/android/service/autofill/FillCallback.java @@ -18,7 +18,6 @@ package android.service.autofill; import android.annotation.Nullable; import android.app.Activity; -import android.os.Bundle; import android.os.RemoteException; /** @@ -38,8 +37,8 @@ public final class FillCallback { /** * Notifies the Android System that an - * {@link AutofillService#onFillRequest(android.app.assist.AssistStructure, Bundle, - * int, android.os.CancellationSignal, FillCallback)} was successfully fulfilled by the service. + * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, + * FillCallback)} was successfully fulfilled by the service. * * @param response autofill information for that activity, or {@code null} when the activity * cannot be autofilled (for example, if it only contains read-only fields). See @@ -57,9 +56,8 @@ public final class FillCallback { /** * Notifies the Android System that an - * {@link AutofillService#onFillRequest(android.app.assist.AssistStructure, - * Bundle, int, android.os.CancellationSignal, FillCallback)} - * could not be fulfilled by the service. + * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, + * FillCallback)} could not be fulfilled by the service. * * @param message error message to be displayed to the user. */ diff --git a/core/java/android/service/autofill/FillEventHistory.aidl b/core/java/android/service/autofill/FillEventHistory.aidl new file mode 100644 index 000000000000..3c4852423d1b --- /dev/null +++ b/core/java/android/service/autofill/FillEventHistory.aidl @@ -0,0 +1,19 @@ +/** + * 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. + */ + +package android.service.autofill; + +parcelable FillEventHistory; diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java new file mode 100644 index 000000000000..3d72fccece9c --- /dev/null +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -0,0 +1,208 @@ +/* + * 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. + */ + +package android.service.autofill; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.content.IntentSender; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.autofill.AutofillId; +import android.widget.RemoteViews; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** + * Describes what happened after the latest call to {@link FillCallback#onSuccess(FillResponse)}. + */ +public final class FillEventHistory implements Parcelable { + /** + * Not in parcel. The UID of the {@link AutofillService} that created the {@link FillResponse}. + */ + private final int mServiceUid; + + @Nullable private final Bundle mClientState; + @Nullable List<Event> mEvents; + + /** + * Gets the UID of the {@link AutofillService} that created the {@link FillResponse}. + * + * @return The UID of the {@link AutofillService} + * + * @hide + */ + public int getServiceUid() { + return mServiceUid; + } + + /** + * Returns the client state of the {@link FillResponse}. + * + * @return The client state set by the last {@link FillResponse} + */ + @Nullable public Bundle getClientState() { + return mClientState; + } + + /** + * Returns the events occurred after the latest call to + * {@link FillCallback#onSuccess(FillResponse)}. + * + * @return The list of events or {@code null} if non occurred. + */ + @Nullable public List<Event> getEvents() { + return mEvents; + } + + /** + * @hide + */ + public void addEvent(Event event) { + if (mEvents == null) { + mEvents = new ArrayList<>(1); + } + mEvents.add(event); + } + + /** + * @hide + */ + public FillEventHistory(int serviceUid, @Nullable Bundle clientState) { + mClientState = clientState; + mServiceUid = serviceUid; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBundle(mClientState); + + if (mEvents == null) { + dest.writeInt(0); + } else { + dest.writeInt(mEvents.size()); + + int numEvents = mEvents.size(); + for (int i = 0; i < numEvents; i++) { + Event event = mEvents.get(i); + dest.writeInt(event.getType()); + dest.writeString(event.getDatasetId()); + } + } + } + + /** + * Description of an event that occured after the latest call to + * {@link FillCallback#onSuccess(FillResponse)}. + */ + public static final class Event { + /** + * A dataset was selected. The dataset selected can be read from {@link #getDatasetId()}. + */ + public static final int TYPE_DATASET_SELECTED = 0; + + /** + * A {@link Dataset.Builder#setAuthentication(IntentSender) dataset authentication} was + * selected. The dataset authenticated can be read from {@link #getDatasetId()}. + */ + public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; + + /** + * A {@link FillResponse.Builder#setAuthentication(AutofillId[], IntentSender, RemoteViews) + * fill response authentication} was selected. + */ + public static final int TYPE_AUTHENTICATION_SELECTED = 2; + + /** A save UI was shown. */ + public static final int TYPE_SAVE_SHOWN = 3; + + /** @hide */ + @IntDef( + value = {TYPE_DATASET_SELECTED, + TYPE_DATASET_AUTHENTICATION_SELECTED, + TYPE_AUTHENTICATION_SELECTED, + TYPE_SAVE_SHOWN}) + @Retention(RetentionPolicy.SOURCE) + @interface EventIds{} + + @EventIds private final int mEventType; + @Nullable private final String mDatasetId; + + /** + * Returns the type of the event. + * + * @return The type of the event + */ + public int getType() { + return mEventType; + } + + /** + * Returns the id of dataset the id was on. + * + * @return The id of dataset, or {@code null} the event is not associated with a dataset. + */ + @Nullable public String getDatasetId() { + return mDatasetId; + } + + /** + * Creates a new event. + * + * @param eventType The type of the event + * @param datasetId The dataset the event was on, or {@code null} if the event was on the + * whole response. + * + * @hide + */ + public Event(int eventType, String datasetId) { + mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_SAVE_SHOWN, + "eventType"); + mDatasetId = datasetId; + } + } + + public static final Parcelable.Creator<FillEventHistory> CREATOR = + new Parcelable.Creator<FillEventHistory>() { + @Override + public FillEventHistory createFromParcel(Parcel parcel) { + FillEventHistory selection = new FillEventHistory(0, parcel.readBundle()); + + int numEvents = parcel.readInt(); + for (int i = 0; i < numEvents; i++) { + selection.addEvent(new Event(parcel.readInt(), parcel.readString())); + } + + return selection; + } + + @Override + public FillEventHistory[] newArray(int size) { + return new FillEventHistory[size]; + } + }; +} diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index 8c8060a608f0..002536517a87 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -32,8 +32,7 @@ import java.util.ArrayList; /** * Response for a {@link - * AutofillService#onFillRequest(android.app.assist.AssistStructure, - * Bundle, int, android.os.CancellationSignal, FillCallback)}. + * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}. * * <p>The response typically contains one or more {@link Dataset}s, each representing a set of * fields that can be autofilled together, and the Android system displays a dataset picker UI @@ -258,6 +257,19 @@ public final class FillResponse implements Parcelable { } /** + * Specifies views that should not trigger new + * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, + * FillCallback)} requests. + * + * <p>This is typically used when the service cannot autofill the view; for example, an + * {@code EditText} representing a captcha. + */ + public Builder setIgnoredIds(AutofillId...ids) { + // TODO: implement + return this; + } + + /** * Adds a new {@link Dataset} to this response. * * @return This builder. @@ -289,6 +301,9 @@ public final class FillResponse implements Parcelable { return this; } + /** + * @deprecated Use {@link #setClientState(Bundle)} instead. + */ @Deprecated public Builder setExtras(@Nullable Bundle extras) { throwIfDestroyed(); @@ -299,11 +314,9 @@ public final class FillResponse implements Parcelable { /** * Sets a {@link Bundle state} that will be passed to subsequent APIs that * manipulate this response. For example, they are passed to subsequent - * calls to {@link AutofillService#onFillRequest( - * android.app.assist.AssistStructure, Bundle, int, - * android.os.CancellationSignal, FillCallback)} and {@link AutofillService#onSaveRequest( - * android.app.assist.AssistStructure, Bundle, SaveCallback)}. You can use - * this to store intermediate state that is persistent across multiple + * calls to {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, + * FillCallback)} and {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}. + * You can use this to store intermediate state that is persistent across multiple * fill requests and the subsequent save request. * * <p>If this method is called on multiple {@link FillResponse} objects for the same diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java index 2c4ba6c57213..3a7013841729 100644 --- a/core/java/android/service/autofill/SaveCallback.java +++ b/core/java/android/service/autofill/SaveCallback.java @@ -17,7 +17,6 @@ package android.service.autofill; import android.app.Activity; -import android.os.Bundle; import android.os.RemoteException; /** @@ -35,8 +34,8 @@ public final class SaveCallback { /** * Notifies the Android System that an - * {@link AutofillService#onSaveRequest (android.app.assist.AssistStructure, Bundle, - * SaveCallback)} was successfully fulfilled by the service. + * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} was successfully fulfilled + * by the service. * * @throws RuntimeException if an error occurred while calling the Android System. */ @@ -52,8 +51,8 @@ public final class SaveCallback { /** * Notifies the Android System that an - * {@link AutofillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, - * SaveCallback)} could not be fulfilled by the service. + * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} could not be fulfilled + * by the service. * * @param message error message to be displayed to the user. * diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 7f960dff0bdf..f7964447fb7b 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -40,7 +40,7 @@ import java.util.Arrays; /** * Information used to indicate that an {@link AutofillService} is interested on saving the * user-inputed data for future use, through a - * {@link AutofillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, SaveCallback)} + * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} * call. * * <p>A {@link SaveInfo} is always associated with a {@link FillResponse}, and it contains at least @@ -94,7 +94,7 @@ import java.util.Arrays; * </pre> * * The - * {@link AutofillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, SaveCallback)} + * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} * is triggered after a call to {@link AutofillManager#commit()}, but only when all conditions * below are met: * @@ -153,13 +153,27 @@ public final class SaveInfo implements Parcelable { @Retention(RetentionPolicy.SOURCE) @interface SaveDataType{} + /** + * Usually {@link AutofillService#onSaveRequest(AssistStructure, Bundle, SaveCallback)} + * is called once the activity finishes. If this flag is set it is called once all saved views + * become invisible. + */ + public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 0x1; + + /** @hide */ + @IntDef( + flag = true, + value = {FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE}) + @Retention(RetentionPolicy.SOURCE) + @interface SaveInfoFlags{} + private final @SaveDataType int mType; private final CharSequence mNegativeActionTitle; private final IntentSender mNegativeActionListener; private final AutofillId[] mRequiredIds; private final AutofillId[] mOptionalIds; private final CharSequence mDescription; - private final boolean mSaveOnAllViewsInvisible; + private final int mFlags; private SaveInfo(Builder builder) { mType = builder.mType; @@ -168,7 +182,7 @@ public final class SaveInfo implements Parcelable { mRequiredIds = builder.mRequiredIds; mOptionalIds = builder.mOptionalIds; mDescription = builder.mDescription; - mSaveOnAllViewsInvisible = builder.mSaveOnAllViewsInvisible; + mFlags = builder.mFlags; } /** @hide */ @@ -197,8 +211,8 @@ public final class SaveInfo implements Parcelable { } /** @hide */ - public boolean saveOnAllViewsInvisible() { - return mSaveOnAllViewsInvisible; + public @SaveInfoFlags int getFlags() { + return mFlags; } /** @hide */ @@ -219,7 +233,7 @@ public final class SaveInfo implements Parcelable { private AutofillId[] mOptionalIds; private CharSequence mDescription; private boolean mDestroyed; - private boolean mSaveOnAllViewsInvisible; + private int mFlags; /** * Creates a new builder. @@ -268,17 +282,15 @@ public final class SaveInfo implements Parcelable { } /** - * Usually {@link AutofillService#onSaveRequest(AssistStructure, Bundle, SaveCallback)} - * is called once the activity finishes. If this property is set it is called once all - * autofillable or saved views become invisible. + * Set flags changing the save behavior. * - * @param saveOnAllViewsInvisible Set to {@code true} if the data should be saved once - * all the views become invisible. + * @param flags {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} or 0. * @return This builder. */ - public @NonNull Builder setSaveOnAllViewsInvisible(boolean saveOnAllViewsInvisible) { + public @NonNull Builder setFlags(@SaveInfoFlags int flags) { throwIfDestroyed(); - mSaveOnAllViewsInvisible = saveOnAllViewsInvisible; + + mFlags = Preconditions.checkFlagsArgument(flags, FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE); return this; } @@ -378,7 +390,7 @@ public final class SaveInfo implements Parcelable { .append(", requiredIds=").append(Arrays.toString(mRequiredIds)) .append(", optionalIds=").append(Arrays.toString(mOptionalIds)) .append(", description=").append(mDescription) - .append(", saveOnNoVisibleTrackedViews=").append(mSaveOnAllViewsInvisible) + .append(", mFlags=").append(mFlags) .append("]").toString(); } @@ -399,7 +411,7 @@ public final class SaveInfo implements Parcelable { parcel.writeParcelable(mNegativeActionListener, flags); parcel.writeParcelableArray(mOptionalIds, flags); parcel.writeCharSequence(mDescription); - parcel.writeBoolean(mSaveOnAllViewsInvisible); + parcel.writeInt(mFlags); } public static final Parcelable.Creator<SaveInfo> CREATOR = new Parcelable.Creator<SaveInfo>() { @@ -413,7 +425,7 @@ public final class SaveInfo implements Parcelable { builder.setNegativeAction(parcel.readCharSequence(), parcel.readParcelable(null)); builder.setOptionalIds(parcel.readParcelableArray(null, AutofillId.class)); builder.setDescription(parcel.readCharSequence()); - builder.setSaveOnAllViewsInvisible(parcel.readBoolean()); + builder.setFlags(parcel.readInt()); return builder.build(); } diff --git a/core/java/android/util/IconDrawableFactory.java b/core/java/android/util/IconDrawableFactory.java new file mode 100644 index 000000000000..b07942ff7f9d --- /dev/null +++ b/core/java/android/util/IconDrawableFactory.java @@ -0,0 +1,112 @@ +/* + * 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. + */ +package android.util; + +import android.annotation.UserIdInt; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Utility class to load app drawables with appropriate badging. + * + * @hide + */ +public class IconDrawableFactory { + + protected final Context mContext; + protected final PackageManager mPm; + protected final UserManager mUm; + protected final LauncherIcons mLauncherIcons; + protected final boolean mEmbedShadow; + + private IconDrawableFactory(Context context, boolean embedShadow) { + mContext = context; + mPm = context.getPackageManager(); + mUm = context.getSystemService(UserManager.class); + mLauncherIcons = new LauncherIcons(context); + mEmbedShadow = embedShadow; + } + + protected boolean needsBadging(ApplicationInfo appInfo, @UserIdInt int userId) { + return appInfo.isInstantApp() || mUm.isManagedProfile(userId); + } + + public Drawable getBadgedIcon(ApplicationInfo appInfo) { + return getBadgedIcon(appInfo, UserHandle.getUserId(appInfo.uid)); + } + + public Drawable getBadgedIcon(ApplicationInfo appInfo, @UserIdInt int userId) { + return getBadgedIcon(appInfo, appInfo, userId); + } + + public Drawable getBadgedIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo, + @UserIdInt int userId) { + Drawable icon = mPm.loadUnbadgedItemIcon(itemInfo, appInfo); + if (!mEmbedShadow && !needsBadging(appInfo, userId)) { + return icon; + } + + // Before badging, add shadow to adaptive icon if needed. + icon = mLauncherIcons.wrapIconDrawableWithShadow(icon); + if (appInfo.isInstantApp()) { + int badgeColor = Resources.getSystem().getColor( + com.android.internal.R.color.instant_app_badge, null); + icon = mLauncherIcons.getBadgedDrawable(icon, + com.android.internal.R.drawable.ic_instant_icon_badge_bolt, + badgeColor); + } + if (mUm.isManagedProfile(userId)) { + icon = mLauncherIcons.getBadgedDrawable(icon, + com.android.internal.R.drawable.ic_corp_icon_badge_case, + getUserBadgeColor(mUm, userId)); + } + return icon; + } + + // Should have enough colors to cope with UserManagerService.getMaxManagedProfiles() + @VisibleForTesting + public static final int[] CORP_BADGE_COLORS = new int[] { + com.android.internal.R.color.profile_badge_1, + com.android.internal.R.color.profile_badge_2, + com.android.internal.R.color.profile_badge_3 + }; + + public static int getUserBadgeColor(UserManager um, @UserIdInt int userId) { + int badge = um.getManagedProfileBadge(userId); + if (badge < 0) { + badge = 0; + } + int resourceId = CORP_BADGE_COLORS[badge % CORP_BADGE_COLORS.length]; + return Resources.getSystem().getColor(resourceId, null); + } + + public static IconDrawableFactory newInstance(Context context) { + return new IconDrawableFactory(context, true); + } + + public static IconDrawableFactory newInstance(Context context, boolean embedShadow) { + return new IconDrawableFactory(context, embedShadow); + } +} diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java index 89b9646e54b3..402bef914421 100644 --- a/core/java/android/util/LauncherIcons.java +++ b/core/java/android/util/LauncherIcons.java @@ -21,10 +21,11 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.PaintFlagsDrawFilter; +import android.graphics.Rect; import android.graphics.drawable.AdaptiveIconDrawable; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.DrawableWrapper; +import android.graphics.drawable.LayerDrawable; /** * Utility class to handle icon treatments (e.g., shadow generation) for the Launcher icons. @@ -32,78 +33,152 @@ import android.graphics.drawable.Drawable; */ public final class LauncherIcons { - private final Paint mPaint = new Paint(); - private final Canvas mCanvas = new Canvas(); + // Percent of actual icon size + private static final float ICON_SIZE_BLUR_FACTOR = 0.5f/48; + // Percent of actual icon size + private static final float ICON_SIZE_KEY_SHADOW_DELTA_FACTOR = 1f/48; private static final int KEY_SHADOW_ALPHA = 61; private static final int AMBIENT_SHADOW_ALPHA = 30; - private static final float BLUR_FACTOR = 0.5f / 48; - private int mShadowInset; - private Bitmap mShadowBitmap; - private int mIconSize; - private Resources mRes; + + private final SparseArray<Bitmap> mShadowCache = new SparseArray<>(); + private final int mIconSize; + private final Resources mRes; public LauncherIcons(Context context) { mRes = context.getResources(); - DisplayMetrics metrics = mRes.getDisplayMetrics(); - mShadowInset = (int)(2 * metrics.density); - mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, - Paint.FILTER_BITMAP_FLAG)); - mIconSize = (int) mRes.getDimensionPixelSize(android.R.dimen.app_icon_size); - } - - /** - * Draw the drawable into a bitmap. - */ - public Bitmap createIconBitmap(Drawable icon) { - final Bitmap bitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888); - mPaint.setAlpha(255); - mCanvas.setBitmap(bitmap); - int iconInset = 0; - if (mShadowBitmap != null) { - mCanvas.drawBitmap(mShadowBitmap, 0, 0, mPaint); - iconInset = mShadowInset; - } - - icon.setBounds(iconInset, iconInset, mIconSize - iconInset, - mIconSize - iconInset); - icon.draw(mCanvas); - mCanvas.setBitmap(null); - return bitmap; + mIconSize = mRes.getDimensionPixelSize(android.R.dimen.app_icon_size); } public Drawable wrapIconDrawableWithShadow(Drawable drawable) { if (!(drawable instanceof AdaptiveIconDrawable)) { return drawable; } - AdaptiveIconDrawable d = - (AdaptiveIconDrawable) drawable.getConstantState().newDrawable().mutate(); - getShadowBitmap(d); - Bitmap iconbitmap = createIconBitmap(d); - return new BitmapDrawable(mRes, iconbitmap); + Bitmap shadow = getShadowBitmap((AdaptiveIconDrawable) drawable); + return new ShadowDrawable(shadow, drawable); } private Bitmap getShadowBitmap(AdaptiveIconDrawable d) { - if (mShadowBitmap != null) { - return mShadowBitmap; + int shadowSize = Math.max(mIconSize, d.getIntrinsicHeight()); + synchronized (mShadowCache) { + Bitmap shadow = mShadowCache.get(shadowSize); + if (shadow != null) { + return shadow; + } } - mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8); - mCanvas.setBitmap(mShadowBitmap); + d.setBounds(0, 0, shadowSize, shadowSize); - // Draw key shadow - mPaint.setColor(Color.TRANSPARENT); - float blur = BLUR_FACTOR * mIconSize; - mPaint.setShadowLayer(blur, 0, mShadowInset, KEY_SHADOW_ALPHA << 24); - d.setBounds(mShadowInset, mShadowInset, mIconSize - mShadowInset, mIconSize - mShadowInset); - mCanvas.drawPath(d.getIconMask(), mPaint); + float blur = ICON_SIZE_BLUR_FACTOR * shadowSize; + float keyShadowDistance = ICON_SIZE_KEY_SHADOW_DELTA_FACTOR * shadowSize; + + int bitmapSize = (int) (shadowSize + 2 * blur + keyShadowDistance); + Bitmap shadow = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(shadow); + canvas.translate(blur + keyShadowDistance / 2, blur); + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.TRANSPARENT); // Draw ambient shadow - mPaint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24); - d.setBounds(mShadowInset, 2 * mShadowInset, mIconSize - mShadowInset, mIconSize); - mCanvas.drawPath(d.getIconMask(), mPaint); - mPaint.clearShadowLayer(); + paint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24); + canvas.drawPath(d.getIconMask(), paint); + + // Draw key shadow + canvas.translate(0, keyShadowDistance); + paint.setShadowLayer(blur, 0, 0, KEY_SHADOW_ALPHA << 24); + canvas.drawPath(d.getIconMask(), paint); + + canvas.setBitmap(null); + synchronized (mShadowCache) { + mShadowCache.put(shadowSize, shadow); + } + return shadow; + } + + public Drawable getBadgeDrawable(int foregroundRes, int backgroundColor) { + return getBadgedDrawable(null, foregroundRes, backgroundColor); + } + + public Drawable getBadgedDrawable(Drawable base, int foregroundRes, int backgroundColor) { + Resources sysRes = Resources.getSystem(); + + Drawable badgeShadow = sysRes.getDrawable( + com.android.internal.R.drawable.ic_corp_icon_badge_shadow); + + Drawable badgeColor = sysRes.getDrawable( + com.android.internal.R.drawable.ic_corp_icon_badge_color) + .getConstantState().newDrawable().mutate(); + badgeColor.setTint(backgroundColor); - return mShadowBitmap; + Drawable badgeForeground = sysRes.getDrawable(foregroundRes); + + Drawable[] drawables = base == null + ? new Drawable[] {badgeShadow, badgeColor, badgeForeground } + : new Drawable[] {base, badgeShadow, badgeColor, badgeForeground }; + return new LayerDrawable(drawables); + } + + /** + * A drawable which draws a shadow bitmap behind a drawable + */ + private static class ShadowDrawable extends DrawableWrapper { + + final MyConstantState mState; + + public ShadowDrawable(Bitmap shadow, Drawable dr) { + super(dr); + mState = new MyConstantState(shadow, dr.getConstantState()); + } + + ShadowDrawable(MyConstantState state) { + super(state.mChildState.newDrawable()); + mState = state; + } + + @Override + public ConstantState getConstantState() { + return mState; + } + + @Override + public void draw(Canvas canvas) { + Rect bounds = getBounds(); + canvas.drawBitmap(mState.mShadow, null, bounds, mState.mPaint); + canvas.save(); + // Ratio of child drawable size to shadow bitmap size + float factor = 1 / (1 + 2 * ICON_SIZE_BLUR_FACTOR + ICON_SIZE_KEY_SHADOW_DELTA_FACTOR); + + canvas.translate( + bounds.width() * factor * + (ICON_SIZE_BLUR_FACTOR + ICON_SIZE_KEY_SHADOW_DELTA_FACTOR / 2), + bounds.height() * factor * ICON_SIZE_BLUR_FACTOR); + canvas.scale(factor, factor); + super.draw(canvas); + canvas.restore(); + } + + private static class MyConstantState extends ConstantState { + + final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + final Bitmap mShadow; + final ConstantState mChildState; + + MyConstantState(Bitmap shadow, ConstantState childState) { + mShadow = shadow; + mChildState = childState; + } + + @Override + public Drawable newDrawable() { + return new ShadowDrawable(this); + } + + @Override + public int getChangingConfigurations() { + return mChildState.getChangingConfigurations(); + } + } } } diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java index f47c35580f0f..1ccf16a64ade 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -127,20 +127,23 @@ public class FocusFinder { if (focused == null || focused == root) { return root; } - ViewParent effective = focused.getParent(); + ViewGroup effective = null; + ViewParent nextParent = focused.getParent(); do { - if (effective == root) { - return root; + if (nextParent == root) { + return effective != null ? effective : root; } - ViewGroup vg = (ViewGroup) effective; + ViewGroup vg = (ViewGroup) nextParent; if (vg.getTouchscreenBlocksFocus() && focused.getContext().getPackageManager().hasSystemFeature( PackageManager.FEATURE_TOUCHSCREEN) && vg.isKeyboardNavigationCluster()) { - return vg; + // Don't stop and return here because the cluster could be nested and we only + // care about the top-most one. + effective = vg; } - effective = effective.getParent(); - } while (effective != null); + nextParent = nextParent.getParent(); + } while (nextParent instanceof ViewGroup); return root; } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 1a71679449a4..9d40895f6ad9 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -295,7 +295,15 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb @Override protected void onDetachedFromWindow() { - getViewRootImpl().removeWindowStoppedCallback(this); + ViewRootImpl viewRoot = getViewRootImpl(); + // It's possible to create a SurfaceView using the default constructor and never + // attach it to a view hierarchy, this is a common use case when dealing with + // OpenGL. A developer will probably create a new GLSurfaceView, and let it manage + // the lifecycle. Instead of attaching it to a view, he/she can just pass + // the SurfaceHolder forward, most live wallpapers do it. + if (viewRoot != null) { + viewRoot.removeWindowStoppedCallback(this); + } mAttachedToWindow = false; if (mGlobalListenersAdded) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 7d2d77e251a9..9df7de830ac9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1135,27 +1135,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @IntDef({ IMPORTANT_FOR_AUTOFILL_AUTO, IMPORTANT_FOR_AUTOFILL_YES, - IMPORTANT_FOR_AUTOFILL_NO + IMPORTANT_FOR_AUTOFILL_NO, + IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, + IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS }) @Retention(RetentionPolicy.SOURCE) public @interface AutofillImportance {} /** - * Automatically determine whether a view is important for auto-fill. + * Automatically determine whether a view is important for autofill. */ public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; /** - * The view is important for important for auto-fill. + * The view is important for autofill, and its children (if any) will be traversed. */ public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; /** - * The view is not important for auto-fill. + * The view is not important for autofill, and its children (if any) will be traversed. */ public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; /** + * The view is important for autofill, but its children (if any) will not be traversed. + */ + public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; + + /** + * The view is not important for autofill, and its children (if any) will not be traversed. + */ + public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; + + /** * This view is enabled. Interpretation varies by subclass. * Use with ENABLED_MASK when calling setFlags. * {@hide} @@ -7568,7 +7580,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * should use {@link #setImportantForAutofill(int)} instead. * * <p><strong>Note:</strong> returning {@code false} does not guarantee the view will be - * excluded from the structure; for example, if the user explicitly requested auto-fill, the + * excluded from the structure; for example, if the user explicitly requested autofill, the * View might be always included. * * <p>This decision applies just for the view, not its children - if the view children are not @@ -9768,6 +9780,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters + * will be ignored. + * + * @return the keyboard navigation cluster that this view is in (can be this view) + * or {@code null} if not in one + */ + View findKeyboardNavigationCluster() { + if (mParent instanceof View) { + View cluster = ((View) mParent).findKeyboardNavigationCluster(); + if (cluster != null) { + return cluster; + } else if (isKeyboardNavigationCluster()) { + return this; + } + } + return null; + } + + /** * Set whether this view is a root of a keyboard navigation cluster. * * @param isCluster If true, this view is a root of a cluster. @@ -9789,9 +9820,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ - public void setFocusedInCluster() { - if (mParent instanceof ViewGroup) { - ((ViewGroup) mParent).setFocusInCluster(this); + public final void setFocusedInCluster() { + View top = findKeyboardNavigationCluster(); + if (top == this) { + return; + } + ViewParent parent = mParent; + View child = this; + while (parent instanceof ViewGroup) { + ((ViewGroup) parent).setFocusedInCluster(child); + if (parent == top) { + return; + } + child = (View) parent; + parent = parent.getParent(); } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index f9eb25da642a..d400011391fd 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -807,33 +807,27 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mDefaultFocus != null || super.hasDefaultFocus(); } - void setFocusInCluster(View child) { - // Stop at the root of the cluster - if (child.isKeyboardNavigationCluster()) { - return; - } - + void setFocusedInCluster(View child) { mFocusedInCluster = child; - - if (mParent instanceof ViewGroup) { - ((ViewGroup) mParent).setFocusInCluster(this); - } } - void clearFocusInCluster(View child) { + /** + * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing + * it. + * <br> + * This is intended to be run on {@code child}'s immediate parent. This is necessary because + * the chain is sometimes cleared after {@code child} has been detached. + */ + void clearFocusedInCluster(View child) { if (mFocusedInCluster != child) { return; } - - if (child.isKeyboardNavigationCluster()) { - return; - } - - mFocusedInCluster = null; - - if (mParent instanceof ViewGroup) { - ((ViewGroup) mParent).clearFocusInCluster(this); - } + View top = findKeyboardNavigationCluster(); + ViewParent parent = this; + do { + ((ViewGroup) parent).mFocusedInCluster = null; + parent = parent.getParent(); + } while (parent != top && parent instanceof ViewGroup); } @Override @@ -1281,7 +1275,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) { if (touchscreenBlocksFocus) { mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS; - if (hasFocus()) { + if (hasFocus() && !isKeyboardNavigationCluster()) { final View focusedChild = getDeepestFocusedChild(); if (!focusedChild.isFocusableInTouchMode()) { final View newFocus = focusSearch(FOCUS_FORWARD); @@ -1316,7 +1310,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // cluster, focus is free to move around within it. return getTouchscreenBlocksFocus() && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN) - && (!hasFocus() || !isKeyboardNavigationCluster()); + && !(isKeyboardNavigationCluster() + && (hasFocus() || (findKeyboardNavigationCluster() != this))); } @Override @@ -3217,8 +3212,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) { - if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster() - && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS + if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE && mFocusedInCluster.restoreFocusInCluster(direction)) { return true; @@ -5182,7 +5176,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearChildFocus = true; } if (view == mFocusedInCluster) { - clearFocusInCluster(view); + clearFocusedInCluster(view); } view.clearAccessibilityFocus(); @@ -5302,7 +5296,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearDefaultFocus = view; } if (view == mFocusedInCluster) { - clearFocusInCluster(view); + clearFocusedInCluster(view); } view.clearAccessibilityFocus(); @@ -5458,7 +5452,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager clearDefaultFocus(child); } if (child == mFocusedInCluster) { - clearFocusInCluster(child); + clearFocusedInCluster(child); } child.clearAccessibilityFocus(); diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index b157709e5261..92b0d9817fc0 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -326,8 +326,8 @@ public abstract class ViewStructure { /** * Sets whether the data on this node is sensitive; if it is, then its content (text, autofill * value, etc..) is striped before calls to {@link - * android.service.autofill.AutofillService#onFillRequest(android.app.assist.AssistStructure, - * Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback)}. + * android.service.autofill.AutofillService#onFillRequest(android.service.autofill.FillRequest, + * android.os.CancellationSignal, android.service.autofill.FillCallback)}. * * <p>By default, all nodes are assumed to be sensitive, and only nodes that does not have PII * (Personally Identifiable Information - sensitive data such as email addresses, credit card @@ -336,8 +336,8 @@ public abstract class ViewStructure { * * <p>Notice that the content of even sensitive nodes are sent to the service (through the * {@link - * android.service.autofill.AutofillService#onSaveRequest(android.app.assist.AssistStructure, - * Bundle, android.service.autofill.SaveCallback)} call) when the user consented to save + * android.service.autofill.AutofillService#onSaveRequest(android.service.autofill.SaveRequest, + * android.service.autofill.SaveCallback)} call) when the user consented to save * thedata, so it is important to set the content of sensitive nodes as well, but mark them as * sensitive. * diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index f9f400d83b09..8ed0762a9e92 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -31,6 +31,8 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; +import android.service.autofill.AutofillService; +import android.service.autofill.FillEventHistory; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -105,6 +107,7 @@ public final class AutofillManager { * * @deprecated Use {@link android.service.autofill.FillRequest#FLAG_MANUAL_REQUEST} */ + // TODO(b/33197203): remove @Deprecated public static final int FLAG_MANUAL_REQUEST = 0x1; @@ -334,6 +337,20 @@ public final class AutofillManager { } /** + * Should always be called from {@link AutofillService#getFillEventHistory()}. + * + * @hide + */ + @Nullable public FillEventHistory getFillEventHistory() { + try { + return mService.getFillEventHistory(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return null; + } + } + + /** * Explicitly requests a new autofill context. * * <p>Normally, the autofill context is automatically started when autofillable views are diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index 68b3ccabc8be..df777c4a6869 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -19,6 +19,7 @@ package android.view.autofill; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; +import android.service.autofill.FillEventHistory; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import android.view.autofill.IAutoFillManagerClient; @@ -33,6 +34,7 @@ interface IAutoFillManager { int startSession(IBinder activityToken, IBinder windowToken, in IBinder appCallback, in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags, String packageName); + FillEventHistory getFillEventHistory(); boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback); void setWindow(int sessionId, in IBinder windowToken); void updateSession(int sessionId, in AutofillId id, in Rect bounds, diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 4fb7b19f7bf7..0d3baa8361ba 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -146,7 +146,7 @@ public class Editor { private static final String UNDO_OWNER_TAG = "Editor"; // Ordering constants used to place the Action Mode or context menu items in their menu. - private static final int MENU_ITEM_ORDER_ASSIST = 1; + private static final int MENU_ITEM_ORDER_ASSIST = 0; private static final int MENU_ITEM_ORDER_UNDO = 2; private static final int MENU_ITEM_ORDER_REDO = 3; private static final int MENU_ITEM_ORDER_CUT = 4; @@ -156,8 +156,8 @@ public class Editor { private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 8; private static final int MENU_ITEM_ORDER_SELECT_ALL = 9; private static final int MENU_ITEM_ORDER_REPLACE = 10; - private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 11; - private static final int MENU_ITEM_ORDER_AUTOFILL = 12; + private static final int MENU_ITEM_ORDER_AUTOFILL = 11; + private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100; // Each Editor manages its own undo stack. private final UndoManager mUndoManager = new UndoManager(); @@ -6322,9 +6322,10 @@ public class Editor { * Adds "PROCESS_TEXT" menu items to the specified menu. */ public void onInitializeMenu(Menu menu) { - int i = 0; + final int size = mSupportedActivities.size(); loadSupportedActivities(); - for (ResolveInfo resolveInfo : mSupportedActivities) { + for (int i = 0; i < size; i++) { + final ResolveInfo resolveInfo = mSupportedActivities.get(i); menu.add(Menu.NONE, Menu.NONE, Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i++, getLabel(resolveInfo)) diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index f9f10af85b69..f1a3ff54ed80 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8196,9 +8196,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mTempTextPaint.set(getPaint()); mTempTextPaint.setTextSize(suggestedSizeInPx); + final int availableWidth = mHorizontallyScrolling + ? VERY_WIDE + : getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight(); final StaticLayout.Builder layoutBuilder = StaticLayout.Builder.obtain( - text, 0, text.length(), mTempTextPaint, - getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight()); + text, 0, text.length(), mTempTextPaint, availableWidth); layoutBuilder.setAlignment(getLayoutAlignment()) .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier()) diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java index 032c7750c1d6..b9ed96395130 100644 --- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java +++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java @@ -34,6 +34,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.internal.R; +import com.android.internal.widget.ResolverDrawerLayout; import java.util.ArrayList; import java.util.Collections; @@ -56,6 +57,11 @@ public class AccessibilityButtonChooserActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.accessibility_button_chooser); + final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); + if (rdl != null) { + rdl.setOnDismissedListener(this::finish); + } + String component = Settings.Secure.getString(getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT); if (TextUtils.isEmpty(component)) { diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java index cc3f58cb0c3d..e28079fd5cdd 100644 --- a/core/java/com/android/internal/os/WebViewZygoteInit.java +++ b/core/java/com/android/internal/os/WebViewZygoteInit.java @@ -70,6 +70,7 @@ class WebViewZygoteInit { @Override protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { + Log.i(TAG, "Beginning package preload"); // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that // our children will reuse the same classloader instead of creating their own. // This enables us to preload Java and native code in the webview zygote process and @@ -97,6 +98,7 @@ class WebViewZygoteInit { IllegalAccessException | InvocationTargetException e) { Log.e(TAG, "Exception while preloading package", e); } + Log.i(TAG, "Package preload done"); return false; } } diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 818cc2c2421d..8c71cf7006ff 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -233,6 +233,7 @@ public final class FloatingToolbar { private void doShow() { List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); + tidy(menuItems); if (!isCurrentlyShowing(menuItems) || mWidthChanged) { mPopup.dismiss(); mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); @@ -274,6 +275,36 @@ public final class FloatingToolbar { return menuItems; } + /** + * Update the list of menu items to conform to certain requirements. + */ + private void tidy(List<MenuItem> menuItems) { + int assistItemIndex = -1; + Drawable assistItemDrawable = null; + + final int size = menuItems.size(); + for (int i = 0; i < size; i++) { + final MenuItem menuItem = menuItems.get(i); + + if (menuItem.getItemId() == android.R.id.textAssist) { + assistItemIndex = i; + assistItemDrawable = menuItem.getIcon(); + } + + // Remove icons for all menu items with text. + if (!TextUtils.isEmpty(menuItem.getTitle())) { + menuItem.setIcon(null); + } + } + if (assistItemIndex > -1) { + final MenuItem assistMenuItem = menuItems.remove(assistItemIndex); + // Ensure the assist menu item preserves its icon. + assistMenuItem.setIcon(assistItemDrawable); + // Ensure the assist menu item is always the first item. + menuItems.add(0, assistMenuItem); + } + } + private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) { List<Object> references = new ArrayList<Object>(); for (MenuItem menuItem : menuItems) { diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml deleted file mode 100644 index 89174312aaaf..000000000000 --- a/core/res/res/drawable/ic_corp_badge.xml +++ /dev/null @@ -1,33 +0,0 @@ -<!-- -Copyright (C) 2014 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="20.0dp" - android:height="20.0dp" - android:viewportWidth="20.0" - android:viewportHeight="20.0"> - <path - android:pathData="M10.0,10.0m-10.0,0.0a10.0,10.0 0.0,1.0 1.0,20.0 0.0a10.0,10.0 0.0,1.0 1.0,-20.0 0.0" - android:fillColor="#FF5722"/> - <path - android:pathData="M15.2,6.2L4.8,6.2c-0.5,0.0 -0.9,0.4 -0.9,1.0L3.9,10.0c0.0,0.5 0.4,1.0 0.9,1.0l3.8,0.0l0.0,-1.0l2.9,0.0l0.0,1.0l3.8,0.0c0.5,0.0 1.0,-0.4 1.0,-1.0L16.3,7.1C16.2,6.6 15.8,6.2 15.2,6.2z" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M8.6,12.9l0.0,-1.0L4.3,11.9l0.0,2.4c0.0,0.5 0.4,0.9 0.9,0.9l9.5,0.0c0.5,0.0 0.9,-0.4 0.9,-0.9l0.0,-2.4l-4.3,0.0l0.0,1.0L8.6,12.9z" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M7.1,5.2l0.0,1.0 1.0,0.0 0.0,-1.0 3.799999,0.0 0.0,1.0 1.0,0.0 0.0,-1.0 -1.0,-0.9 -3.799999,0.0z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/core/res/res/drawable/ic_instant_icon_badge_bolt.xml b/core/res/res/drawable/ic_instant_icon_badge_bolt.xml new file mode 100644 index 000000000000..08512b7af310 --- /dev/null +++ b/core/res/res/drawable/ic_instant_icon_badge_bolt.xml @@ -0,0 +1,29 @@ +<!-- +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="64.0dp" + android:height="64.0dp" + android:viewportWidth="64.0" + android:viewportHeight="64.0"> + + <!-- + The path is similar to ic_corp_icon_badge_case, such that it positions on top of + ic_corp_icon_badge_shadow. + --> + <path + android:pathData="M43.9 50.9h4v8l6-12h-4v-8l-6 12z" + android:fillColor="#757575"/> +</vector> diff --git a/core/res/res/layout/accessibility_button_chooser.xml b/core/res/res/layout/accessibility_button_chooser.xml index 0ef785f102bb..480defbd5935 100644 --- a/core/res/res/layout/accessibility_button_chooser.xml +++ b/core/res/res/layout/accessibility_button_chooser.xml @@ -19,7 +19,7 @@ <com.android.internal.widget.ResolverDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:maxWidth="@dimen/resolver_max_width" android:maxCollapsedHeight="256dp" android:maxCollapsedHeightSmall="56dp" @@ -27,11 +27,14 @@ <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" + android:layout_alwaysShow="true" android:orientation="vertical" android:background="?attr/colorBackground" android:paddingTop="8dp" - android:paddingBottom="8dp"> + android:paddingBottom="8dp" + android:paddingStart="?attr/dialogPreferredPadding" + android:paddingEnd="?attr/dialogPreferredPadding"> <TextView android:layout_width="match_parent" @@ -41,8 +44,6 @@ android:text="@string/accessibility_button_prompt_text" android:gravity="start|center_vertical" android:layout_alignParentStart="true" - android:paddingStart="?attr/dialogPreferredPadding" - android:paddingEnd="?attr/dialogPreferredPadding" android:paddingTop="8dp" android:paddingBottom="8dp"/> @@ -55,20 +56,15 @@ android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:stretchMode="columnWidth" - android:paddingStart="?attr/dialogPreferredPadding" - android:paddingEnd="?attr/dialogPreferredPadding" android:gravity="center"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/accessibility_button_prompt" - android:layout_alwaysShow="true" android:textAppearance="?attr/textAppearanceMedium" android:text="@string/accessibility_button_instructional_text" android:gravity="start|center_vertical" - android:paddingStart="?attr/dialogPreferredPadding" - android:paddingEnd="?attr/dialogPreferredPadding" android:paddingTop="8dp" android:paddingBottom="8dp" android:visibility="gone"/> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 937fc6fba247..536906cde30c 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -171,6 +171,9 @@ <color name="profile_badge_2">#ff000000</color><!-- Black --> <color name="profile_badge_3">#ff22f033</color><!-- Green --> + <!-- Default instant app badge color --> + <color name="instant_app_badge">#FFFFFFFF</color><!-- White --> + <!-- Multi-sim sim colors --> <color name="Teal_700">#ff00796b</color> <color name="Teal_800">#ff00695c</color> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f2da8457601c..907294d744f7 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1322,6 +1322,7 @@ <java-symbol type="drawable" name="ic_corp_user_badge" /> <java-symbol type="drawable" name="ic_corp_badge_no_background" /> <java-symbol type="drawable" name="ic_corp_statusbar_icon" /> + <java-symbol type="drawable" name="ic_instant_icon_badge_bolt" /> <java-symbol type="drawable" name="emulator_circular_window_overlay" /> <java-symbol type="drawable" name="sim_light_blue" /> @@ -1353,6 +1354,7 @@ <java-symbol type="color" name="profile_badge_1" /> <java-symbol type="color" name="profile_badge_2" /> <java-symbol type="color" name="profile_badge_3" /> + <java-symbol type="color" name="instant_app_badge" /> <java-symbol type="layout" name="action_bar_home" /> <java-symbol type="layout" name="action_bar_title_item" /> diff --git a/core/tests/coretests/src/android/metrics/LogMakerTest.java b/core/tests/coretests/src/android/metrics/LogMakerTest.java index bab9f631d7d4..63c1f87178aa 100644 --- a/core/tests/coretests/src/android/metrics/LogMakerTest.java +++ b/core/tests/coretests/src/android/metrics/LogMakerTest.java @@ -263,4 +263,32 @@ public class LogMakerTest extends TestCase { assertFalse(a.isSubsetOf(b)); assertFalse(b.isSubsetOf(a)); } + + public void testConstructFromNull() { + new LogMaker(null); + // no promises, just don't throw + } + + public void testConstructFromNullKey() { + Object[] items = new Object[2]; + items[0] = null; + items[1] = "foo"; + new LogMaker(items); + // no promises, just don't throw + } + + public void testConstructFromNullField() { + Object[] items = new Object[2]; + items[0] = 10; + items[1] = null; + new LogMaker(items); + // no promises, just don't throw + } + + public void testConstructFromTruncatedArray() { + Object[] items = new Object[1]; + items[0] = 10; + new LogMaker(items); + // no promises, just don't throw + } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java new file mode 100644 index 000000000000..0acff9bcc305 --- /dev/null +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java @@ -0,0 +1,212 @@ +/* + * 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. + */ + +package android.view.textclassifier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; + +import android.os.LocaleList; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.view.textclassifier.TextClassificationManager; +import android.view.textclassifier.TextClassificationResult; +import android.view.textclassifier.TextClassifier; +import android.view.textclassifier.TextLanguage; +import android.view.textclassifier.TextSelection; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; +import java.util.Locale; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TextClassificationManagerTest { + + private static final LocaleList LOCALES = LocaleList.forLanguageTags("en"); + + private TextClassificationManager mTcm; + private TextClassifier mClassifier; + + @Before + public void setup() { + mTcm = InstrumentationRegistry.getTargetContext() + .getSystemService(TextClassificationManager.class); + mTcm.setTextClassifier(null); + mClassifier = mTcm.getTextClassifier(); + } + + @Test + public void testSmartSelection() { + if (isTextClassifierDisabled()) return; + + String text = "Contact me at droid@android.com"; + String selected = "droid"; + String suggested = "droid@android.com"; + int startIndex = text.indexOf(selected); + int endIndex = startIndex + selected.length(); + int smartStartIndex = text.indexOf(suggested); + int smartEndIndex = smartStartIndex + suggested.length(); + + assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES), + isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL)); + } + + @Test + public void testSmartSelection_url() { + if (isTextClassifierDisabled()) return; + + String text = "Visit http://www.android.com for more information"; + String selected = "http"; + String suggested = "http://www.android.com"; + int startIndex = text.indexOf(selected); + int endIndex = startIndex + selected.length(); + int smartStartIndex = text.indexOf(suggested); + int smartEndIndex = smartStartIndex + suggested.length(); + + assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES), + isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL)); + } + + @Test + public void testTextClassificationResult() { + if (isTextClassifierDisabled()) return; + + String text = "Contact me at droid@android.com"; + String classifiedText = "droid@android.com"; + int startIndex = text.indexOf(classifiedText); + int endIndex = startIndex + classifiedText.length(); + assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES), + isTextClassificationResult(classifiedText, TextClassifier.TYPE_EMAIL)); + } + + @Test + public void testTextClassificationResult_url() { + if (isTextClassifierDisabled()) return; + + String text = "Visit http://www.android.com for more information"; + String classifiedText = "http://www.android.com"; + int startIndex = text.indexOf(classifiedText); + int endIndex = startIndex + classifiedText.length(); + assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES), + isTextClassificationResult(classifiedText, TextClassifier.TYPE_URL)); + } + + @Test + public void testLanguageDetection() { + if (isTextClassifierDisabled()) return; + + String text = "This is a piece of English text"; + assertThat(mTcm.detectLanguages(text), isDetectedLanguage("en")); + + text = "Das ist ein deutscher Text"; + assertThat(mTcm.detectLanguages(text), isDetectedLanguage("de")); + + text = "これは日本語のテキストです"; + assertThat(mTcm.detectLanguages(text), isDetectedLanguage("ja")); + } + + @Test + public void testSetTextClassifier() { + TextClassifier classifier = mock(TextClassifier.class); + mTcm.setTextClassifier(classifier); + assertEquals(classifier, mTcm.getTextClassifier()); + } + + private boolean isTextClassifierDisabled() { + return mClassifier == TextClassifier.NO_OP; + } + + private static Matcher<TextSelection> isTextSelection( + final int startIndex, final int endIndex, final String type) { + return new BaseMatcher<TextSelection>() { + @Override + public boolean matches(Object o) { + if (o instanceof TextSelection) { + TextSelection selection = (TextSelection) o; + return startIndex == selection.getSelectionStartIndex() + && endIndex == selection.getSelectionEndIndex() + && selection.getEntityCount() > 0 + && type.equals(selection.getEntity(0)); + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendValue( + String.format("%d, %d, %s", startIndex, endIndex, type)); + } + }; + } + + private static Matcher<TextClassificationResult> isTextClassificationResult( + final String text, final String type) { + return new BaseMatcher<TextClassificationResult>() { + @Override + public boolean matches(Object o) { + if (o instanceof TextClassificationResult) { + TextClassificationResult result = (TextClassificationResult) o; + return text.equals(result.getText()) + && result.getEntityCount() > 0 + && type.equals(result.getEntity(0)); + // TODO: Include other properties. + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText("text=").appendValue(text) + .appendText(", type=").appendValue(type); + } + }; + } + + private static Matcher<List<TextLanguage>> isDetectedLanguage(final String language) { + return new BaseMatcher<List<TextLanguage>>() { + @Override + public boolean matches(Object o) { + if (o instanceof List) { + List languages = (List) o; + if (!languages.isEmpty()) { + Object o1 = languages.get(0); + if (o1 instanceof TextLanguage) { + TextLanguage lang = (TextLanguage) o1; + return lang.getLanguageCount() > 0 + && new Locale(language).getLanguage() + .equals(lang.getLanguage(0).getLanguage()); + } + } + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendValue(String.format("%s", language)); + } + }; + } +} diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index 3029134251dd..2203b6abb8fd 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -28,6 +28,7 @@ import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; import static android.widget.espresso.TextViewAssertions.hasSelection; +import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; @@ -46,6 +47,11 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.is; +import android.view.ActionMode; +import android.view.Menu; +import android.view.MenuItem; +import android.view.textclassifier.TextClassificationManager; +import android.view.textclassifier.TextClassifier; import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider; import android.support.test.espresso.action.EspressoKey; @@ -71,7 +77,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV @Override public void setUp() throws Exception { super.setUp(); - getActivity(); + getActivity().getSystemService(TextClassificationManager.class) + .setTextClassifier(TextClassifier.NO_OP); } public void testTypedTextIsOnScreen() throws Exception { @@ -676,4 +683,38 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV // hasTransientState should return false when selection is created by API. assertFalse(textView.hasTransientState()); } + + public void testAssistItemIsAtIndexZero() throws Exception { + getActivity().getSystemService(TextClassificationManager.class).setTextClassifier(null); + final TextView textView = (TextView) getActivity().findViewById(R.id.textview); + textView.post(() -> textView.setCustomSelectionActionModeCallback( + new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { + // Create another item at order position 0 to confirm that it will never be + // placed before the textAssist item. + menu.add(Menu.NONE, 0 /* id */, 0 /* order */, "Test"); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode actionMode) {} + })); + final String text = "droid@android.com"; + + onView(withId(R.id.textview)).perform(replaceText(text)); + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@'))); + sleepForFloatingToolbarPopup(); + assertFloatingToolbarItemIndex(android.R.id.textAssist, 0); + } } diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java index 838f4db76165..5206c9b553a6 100644 --- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java +++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java @@ -29,7 +29,13 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.is; +import android.view.MenuItem; +import android.view.ViewGroup; +import java.util.ArrayList; +import java.util.List; +import org.hamcrest.Description; import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; @@ -123,6 +129,39 @@ public class FloatingToolbarEspressoUtils { } /** + * Asserts that the floating toolbar contains a specified item at a specified index. + * + * @param menuItemId id of the menu item + * @param index expected index of the menu item in the floating toolbar + * @throws AssertionError if the assertion fails + */ + public static void assertFloatingToolbarItemIndex(final int menuItemId, final int index) { + onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() { + private List<Integer> menuItemIds = new ArrayList<>(); + + @Override + public boolean matchesSafely(View view) { + collectMenuItemIds(view); + return menuItemIds.size() > index && menuItemIds.get(index) == menuItemId; + } + + @Override + public void describeTo(Description description) {} + + private void collectMenuItemIds(View view) { + if (view.getTag() instanceof MenuItem) { + menuItemIds.add(((MenuItem) view.getTag()).getItemId()); + } else if (view instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) view; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + collectMenuItemIds(viewGroup.getChildAt(i)); + } + } + } + })); + } + + /** * Asserts that the floating toolbar doesn't contain the specified item. * * @param itemLabel label of the item. diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 7a8e4873a7c9..599406cd9e1c 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -916,17 +916,20 @@ public final class Bitmap implements Parcelable { * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to * mark the bitmap as opaque. Doing so will clear the bitmap in black * instead of transparent. - * @param colorSpace The color space of the bitmap. If null or if the config is not - * {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB} is assumed. + * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16}, + * {@link ColorSpace.Named#EXTENDED_SRGB scRGB} is assumed, and if the + * config is not {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB} + * is assumed. * * @throws IllegalArgumentException if the width or height are <= 0, if * Config is Config.HARDWARE (because hardware bitmaps are always * immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB}, - * or if the specified color space's transfer function is not an - * {@link ColorSpace.Rgb.TransferParameters ICC parametric curve} + * if the specified color space's transfer function is not an + * {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}, or if + * the color space is null */ public static Bitmap createBitmap(int width, int height, @NonNull Config config, - boolean hasAlpha, @Nullable ColorSpace colorSpace) { + boolean hasAlpha, @NonNull ColorSpace colorSpace) { return createBitmap(null, width, height, config, hasAlpha, colorSpace); } @@ -950,7 +953,8 @@ public final class Bitmap implements Parcelable { */ public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height, @NonNull Config config, boolean hasAlpha) { - return createBitmap(display, width, height, config, hasAlpha, null); + return createBitmap(display, width, height, config, hasAlpha, + ColorSpace.get(ColorSpace.Named.SRGB)); } /** @@ -967,26 +971,32 @@ public final class Bitmap implements Parcelable { * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to * mark the bitmap as opaque. Doing so will clear the bitmap in black * instead of transparent. - * @param colorSpace The color space of the bitmap. If null or if the config is not - * {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB} is assumed. + * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16}, + * {@link ColorSpace.Named#EXTENDED_SRGB scRGB} is assumed, and if the + * config is not {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB} + * is assumed. * * @throws IllegalArgumentException if the width or height are <= 0, if * Config is Config.HARDWARE (because hardware bitmaps are always * immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB}, - * or if the specified color space's transfer function is not an - * {@link ColorSpace.Rgb.TransferParameters ICC parametric curve} + * if the specified color space's transfer function is not an + * {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}, or if + * the color space is null */ public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height, - @NonNull Config config, boolean hasAlpha, @Nullable ColorSpace colorSpace) { + @NonNull Config config, boolean hasAlpha, @NonNull ColorSpace colorSpace) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } if (config == Config.HARDWARE) { throw new IllegalArgumentException("can't create mutable bitmap with Config.HARDWARE"); } + if (colorSpace == null) { + throw new IllegalArgumentException("can't create bitmap without a color space"); + } Bitmap bm; - if (colorSpace == null || config != Config.ARGB_8888) { + if (config != Config.ARGB_8888) { bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, null, null); } else { if (!(colorSpace instanceof ColorSpace.Rgb)) { diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 7e6756ebfdba..5577f53ee28b 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -41,35 +41,16 @@ public class BitmapShader extends Shader { * @param tileY The tiling mode for y to draw the bitmap in. */ public BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY) { - set(bitmap, tileX, tileY); + this(bitmap, tileX.nativeInt, tileY.nativeInt); } private BitmapShader(Bitmap bitmap, int tileX, int tileY) { - setInternal(bitmap, tileX, tileY); - } - - /** - * Reinitialize the BitmapShader's Bitmap and tile modes. - * - * @param bitmap The bitmap to use inside the shader - * @param tileX The tiling mode for x to draw the bitmap in. - * @param tileY The tiling mode for y to draw the bitmap in. - */ - public void set(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY) { - if (tileX == null || tileY == null) { - throw new IllegalArgumentException(); - } - setInternal(bitmap, tileX.nativeInt, tileY.nativeInt); - } - - private void setInternal(Bitmap bitmap, int tileX, int tileY) { if (bitmap == null) { throw new IllegalArgumentException("Bitmap must be non-null"); } if (bitmap == mBitmap && tileX == mTileX && tileY == mTileY) { return; } - discardNativeInstance(); mBitmap = bitmap; mTileX = tileX; mTileY = tileY; diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java index 61f6cc5ba4ee..9201a2e2310e 100644 --- a/graphics/java/android/graphics/ColorMatrixColorFilter.java +++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java @@ -73,6 +73,8 @@ public class ColorMatrixColorFilter extends ColorFilter { * @see #getColorMatrix(ColorMatrix) * @see #setColorMatrixArray(float[]) * @see ColorMatrix#reset() + * + * @hide */ public void setColorMatrix(@Nullable ColorMatrix matrix) { discardNativeInstance(); @@ -99,6 +101,8 @@ public class ColorMatrixColorFilter extends ColorFilter { * * @throws ArrayIndexOutOfBoundsException if the specified array's * length is < 20 + * + * @hide */ public void setColorMatrixArray(@Nullable float[] array) { // called '...Array' so that passing null isn't ambiguous diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java index 8438bf2cc6b4..e107ea724377 100644 --- a/graphics/java/android/graphics/ComposeShader.java +++ b/graphics/java/android/graphics/ComposeShader.java @@ -59,43 +59,10 @@ public class ComposeShader extends Shader { } private ComposeShader(Shader shaderA, Shader shaderB, int nativeMode) { - setInternal(shaderA, shaderB, nativeMode); - } - - /** - * Reinitialize the ComposeShader's component Shaders and blend mode. - * - * @param shaderA The colors from this shader are seen as the "dst" by the mode - * @param shaderB The colors from this shader are seen as the "src" by the mode - * @param mode The PorterDuff mode that combines the colors from the two shaders. - */ - public void set(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull Xfermode mode) { - setInternal(shaderA, shaderB, mode.porterDuffMode); - } - - /** - * Reinitialize the ComposeShader's component Shaders and blend mode. - * - * @param shaderA The colors from this shader are seen as the "dst" by the mode - * @param shaderB The colors from this shader are seen as the "src" by the mode - * @param mode The PorterDuff mode that combines the colors from the two shaders. - */ - public void set(@NonNull Shader shaderA, @NonNull Shader shaderB, - @NonNull PorterDuff.Mode mode) { - setInternal(shaderA, shaderB, mode.nativeInt); - } - - private void setInternal(Shader shaderA, Shader shaderB, int nativeMode) { if (shaderA == null || shaderB == null) { throw new IllegalArgumentException("Shader parameters must not be null"); } - if (shaderA == mShaderA && shaderB == mShaderB && mPorterDuffMode == nativeMode) { - // no work to do... - return; - } - - discardNativeInstance(); mShaderA = shaderA; mShaderB = shaderB; mPorterDuffMode = nativeMode; @@ -109,16 +76,6 @@ public class ComposeShader extends Shader { mShaderA.getNativeInstance(), mShaderB.getNativeInstance(), mPorterDuffMode); } - @Override - void verifyNativeInstance() { - if (mShaderA.getNativeInstance() != mNativeInstanceShaderA - || mShaderB.getNativeInstance() != mNativeInstanceShaderB) { - // Child shader native instance has been updated, - // so our cached native instance is no longer valid - discard it - discardNativeInstance(); - } - } - /** * @hide */ diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java index b0c145beb649..1578ffb873f0 100644 --- a/graphics/java/android/graphics/LightingColorFilter.java +++ b/graphics/java/android/graphics/LightingColorFilter.java @@ -57,8 +57,6 @@ public class LightingColorFilter extends ColorFilter { /** * Returns the RGB color used to multiply the source color when the * color filter is applied. - * - * @see #setColorMultiply(int) */ @ColorInt public int getColorMultiply() { @@ -71,6 +69,8 @@ public class LightingColorFilter extends ColorFilter { * The alpha channel of this color is ignored. * * @see #getColorMultiply() + * + * @hide */ public void setColorMultiply(@ColorInt int mul) { if (mMul != mul) { @@ -82,8 +82,6 @@ public class LightingColorFilter extends ColorFilter { /** * Returns the RGB color that will be added to the source color * when the color filter is applied. - * - * @see #setColorAdd(int) */ @ColorInt public int getColorAdd() { @@ -96,6 +94,8 @@ public class LightingColorFilter extends ColorFilter { * The alpha channel of this color is ignored. * * @see #getColorAdd() + * + * @hide */ public void setColorAdd(@ColorInt int add) { if (mAdd != add) { diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java index 0e4cd0ae06b6..7139efec9337 100644 --- a/graphics/java/android/graphics/LinearGradient.java +++ b/graphics/java/android/graphics/LinearGradient.java @@ -57,48 +57,12 @@ public class LinearGradient extends Shader { */ public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], @Nullable float positions[], @NonNull TileMode tile) { - set(x0, y0, x1, y1, colors, positions, 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 - */ - public LinearGradient(float x0, float y0, float x1, float y1, - @ColorInt int color0, @ColorInt int color1, - @NonNull TileMode tile) { - set(x0, y0, x1, y1, color0, color1, tile); - } - - /** - * Reinitialize the shader. - * - * @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 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 void set(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"); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } - discardNativeInstance(); mType = TYPE_COLORS_AND_POSITIONS; mX0 = x0; mY0 = y0; @@ -110,7 +74,7 @@ public class LinearGradient extends Shader { } /** - * Reinitialize the shader. + * 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 @@ -120,10 +84,9 @@ public class LinearGradient extends Shader { * @param color1 The color at the end of the gradient line. * @param tile The Shader tiling mode */ - public void set(float x0, float y0, float x1, float y1, + public LinearGradient(float x0, float y0, float x1, float y1, @ColorInt int color0, @ColorInt int color1, @NonNull TileMode tile) { - discardNativeInstance(); mType = TYPE_COLOR_START_AND_COLOR_END; mX0 = x0; mY0 = y0; diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index ccc6eadc3df5..01d5825dd1e0 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -49,6 +49,8 @@ public class PorterDuffColorFilter extends ColorFilter { * * @see Color * @see #setColor(int) + * + * @hide */ @ColorInt public int getColor() { @@ -64,6 +66,8 @@ public class PorterDuffColorFilter extends ColorFilter { * @see Color * @see #getColor() * @see #getMode() + * + * @hide */ public void setColor(@ColorInt int color) { if (mColor != color) { @@ -78,6 +82,8 @@ public class PorterDuffColorFilter extends ColorFilter { * * @see PorterDuff * @see #setMode(android.graphics.PorterDuff.Mode) + * + * @hide */ public PorterDuff.Mode getMode() { return mMode; @@ -90,6 +96,8 @@ public class PorterDuffColorFilter extends ColorFilter { * @see PorterDuff * @see #getMode() * @see #getColor() + * + * @hide */ public void setMode(@NonNull PorterDuff.Mode mode) { if (mode == null) { diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index ae8f7daf0298..f4b11917a415 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -57,39 +57,6 @@ public class RadialGradient extends Shader { public RadialGradient(float centerX, float centerY, float radius, @NonNull @ColorInt int colors[], @Nullable float stops[], @NonNull TileMode tileMode) { - set(centerX, centerY, radius, colors, stops, 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 - */ - public RadialGradient(float centerX, float centerY, float radius, - @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode) { - set(centerX, centerY, radius, centerColor, edgeColor, tileMode); - } - - /** - * Reinitialize the 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 colors The 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 void set(float centerX, float centerY, float radius, - @NonNull @ColorInt int colors[], @Nullable float stops[], @NonNull TileMode tileMode) { if (radius <= 0) { throw new IllegalArgumentException("radius must be > 0"); } @@ -99,7 +66,6 @@ public class RadialGradient extends Shader { if (stops != null && colors.length != stops.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } - discardNativeInstance(); mType = TYPE_COLORS_AND_POSITIONS; mX = centerX; mY = centerY; @@ -110,7 +76,7 @@ public class RadialGradient extends Shader { } /** - * Reinitialize the shader. + * 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 @@ -119,12 +85,11 @@ public class RadialGradient extends Shader { * @param edgeColor The color at the edge of the circle. * @param tileMode The Shader tiling mode */ - public void set(float centerX, float centerY, float radius, + 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"); } - discardNativeInstance(); mType = TYPE_COLOR_CENTER_AND_COLOR_EDGE; mX = centerX; mY = centerY; diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index 8410ab2a1e02..c7447575bd8f 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -105,20 +105,13 @@ public class Shader { return 0; } - void discardNativeInstance() { + private void discardNativeInstance() { if (mNativeInstance != 0) { nativeSafeUnref(mNativeInstance); mNativeInstance = 0; } } - /** - * Callback for subclasses to call {@link #discardNativeInstance()} if the most recently - * constructed native instance is no longer valid. - */ - void verifyNativeInstance() { - } - @Override protected void finalize() throws Throwable { try { @@ -155,9 +148,6 @@ public class Shader { throw new IllegalStateException("attempting to use a finalized Shader"); } - // verify mNativeInstance is valid - verifyNativeInstance(); - if (mNativeInstance == 0) { mNativeInstance = createNativeInstance(mLocalMatrix == null ? 0 : mLocalMatrix.native_instance); diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java index 0a1aef605562..b6b80b4f57dc 100644 --- a/graphics/java/android/graphics/SweepGradient.java +++ b/graphics/java/android/graphics/SweepGradient.java @@ -54,37 +54,6 @@ public class SweepGradient extends Shader { */ public SweepGradient(float cx, float cy, @NonNull @ColorInt int colors[], @Nullable float positions[]) { - set(cx, cy, colors, positions); - } - - /** - * 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 - */ - public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) { - set(cx, cy, color0, color1); - } - - /** - * Reinitialize the shader. - * - * @param cx The x-coordinate of the center - * @param cy The y-coordinate of the center - * @param colors The 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 void set(float cx, float cy, - @NonNull @ColorInt int colors[], @Nullable float positions[]) { if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); } @@ -92,7 +61,6 @@ public class SweepGradient extends Shader { throw new IllegalArgumentException( "color and position arrays must be of equal length"); } - discardNativeInstance(); mType = TYPE_COLORS_AND_POSITIONS; mCx = cx; mCy = cy; @@ -101,15 +69,14 @@ public class SweepGradient extends Shader { } /** - * Reinitialize the shader. + * 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 */ - public void set(float cx, float cy, @ColorInt int color0, @ColorInt int color1) { - discardNativeInstance(); + public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) { mType = TYPE_COLOR_START_AND_COLOR_END; mCx = cx; mCy = cy; diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index d95acff8a38e..3e5e3bfc3bf2 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -390,14 +390,8 @@ bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkCl } bool SkiaCanvas::clipPath(const SkPath* path, SkClipOp op) { - SkRRect roundRect; - if (path->isRRect(&roundRect)) { - this->recordClip(roundRect, op); - mCanvas->clipRRect(roundRect, op); - } else { - this->recordClip(*path, op); - mCanvas->clipPath(*path, op); - } + this->recordClip(*path, op); + mCanvas->clipPath(*path, op); return !mCanvas->isClipEmpty(); } diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index b222a6da9a98..68f46ad27750 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -646,7 +646,10 @@ public class Location implements Parcelable { * * <p>Following this call {@link #hasAltitude} will return false, * and {@link #getAltitude} will return 0.0. + * + * @deprecated use a new Location object for location updates. */ + @Deprecated public void removeAltitude() { mAltitude = 0.0f; mFieldsMask &= ~HAS_ALTITUDE_MASK; @@ -683,7 +686,10 @@ public class Location implements Parcelable { * * <p>Following this call {@link #hasSpeed} will return false, * and {@link #getSpeed} will return 0.0. + * + * @deprecated use a new Location object for location updates. */ + @Deprecated public void removeSpeed() { mSpeed = 0.0f; mFieldsMask &= ~HAS_SPEED_MASK; @@ -733,7 +739,10 @@ public class Location implements Parcelable { * * <p>Following this call {@link #hasBearing} will return false, * and {@link #getBearing} will return 0.0. + * + * @deprecated use a new Location object for location updates. */ + @Deprecated public void removeBearing() { mBearing = 0.0f; mFieldsMask &= ~HAS_BEARING_MASK; @@ -790,7 +799,10 @@ public class Location implements Parcelable { * * <p>Following this call {@link #hasAccuracy} will return false, and * {@link #getAccuracy} will return 0.0. + * + * @deprecated use a new Location object for location updates. */ + @Deprecated public void removeAccuracy() { mHorizontalAccuracyMeters = 0.0f; mFieldsMask &= ~HAS_HORIZONTAL_ACCURACY_MASK; @@ -839,7 +851,11 @@ public class Location implements Parcelable { * * <p>Following this call {@link #hasVerticalAccuracy} will return false, and * {@link #getVerticalAccuracyMeters} will return 0.0. + * + * @deprecated use a new Location object for location updates. + * @removed */ + @Deprecated public void removeVerticalAccuracy() { mVerticalAccuracyMeters = 0.0f; mFieldsMask &= ~HAS_VERTICAL_ACCURACY_MASK; @@ -883,7 +899,11 @@ public class Location implements Parcelable { * * <p>Following this call {@link #hasSpeedAccuracy} will return false, and * {@link #getSpeedAccuracyMetersPerSecond} will return 0.0. + * + * @deprecated use a new Location object for location updates. + * @removed */ + @Deprecated public void removeSpeedAccuracy() { mSpeedAccuracyMetersPerSecond = 0.0f; mFieldsMask &= ~HAS_SPEED_ACCURACY_MASK; @@ -927,7 +947,11 @@ public class Location implements Parcelable { * * <p>Following this call {@link #hasBearingAccuracy} will return false, and * {@link #getBearingAccuracyDegrees} will return 0.0. + * + * @deprecated use a new Location object for location updates. + * @removed */ + @Deprecated public void removeBearingAccuracy() { mBearingAccuracyDegrees = 0.0f; mFieldsMask &= ~HAS_BEARING_ACCURACY_MASK; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 9386246bd128..d5efc971d1fd 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1007,13 +1007,14 @@ public class MediaPlayer extends PlayerBase * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @param headers the headers to be sent together with the request for the data - * Note that the cross domain redirection is allowed by default, but that can be - * changed with key/value pairs through the headers parameter with - * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value - * to disallow or allow cross domain redirection. * The headers must not include cookies. Instead, use the cookies param. * @param cookies the cookies to be sent together with the request * @throws IllegalStateException if it is called in an invalid state + * + * <p><strong>Note</strong> that the cross domain redirection is allowed by default, + * but that can be changed with key/value pairs through the headers parameter with + * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to + * disallow or allow cross domain redirection. */ public void setDataSource(@NonNull Context context, @NonNull Uri uri, @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) @@ -1056,11 +1057,12 @@ public class MediaPlayer extends PlayerBase * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @param headers the headers to be sent together with the request for the data - * Note that the cross domain redirection is allowed by default, but that can be - * changed with key/value pairs through the headers parameter with - * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value - * to disallow or allow cross domain redirection. * @throws IllegalStateException if it is called in an invalid state + * + * <p><strong>Note</strong> that the cross domain redirection is allowed by default, + * but that can be changed with key/value pairs through the headers parameter with + * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to + * disallow or allow cross domain redirection. */ public void setDataSource(@NonNull Context context, @NonNull Uri uri, @Nullable Map<String, String> headers) @@ -1981,7 +1983,7 @@ public class MediaPlayer extends PlayerBase mOnSubtitleDataListener = null; // Modular DRM clean up - mOnDrmConfigListener = null; + mOnDrmConfigHelper = null; mOnDrmInfoHandlerDelegate = null; mOnDrmPreparedHandlerDelegate = null; resetDrmState(); @@ -3905,11 +3907,11 @@ public class MediaPlayer extends PlayerBase * 'securityLevel', which has to be set after DRM scheme creation but * before the DRM session is opened. * - * The only allowed DRM calls in this listener are getDrmPropertyString - * and setDrmPropertyString. + * The only allowed DRM calls in this listener are {@code getDrmPropertyString} + * and {@code setDrmPropertyString}. * */ - public interface OnDrmConfigListener + public interface OnDrmConfigHelper { /** * Called to give the app the opportunity to configure DRM before the session is created @@ -3922,19 +3924,19 @@ public class MediaPlayer extends PlayerBase /** * Register a callback to be invoked for configuration of the DRM object before * the session is created. - * The callback will be invoked synchronously half-way into the execution + * The callback will be invoked synchronously during the execution * of {@link #prepareDrm(UUID uuid)}. * * @param listener the callback that will be run */ - public void setOnDrmConfigListener(OnDrmConfigListener listener) + public void setOnDrmConfigHelper(OnDrmConfigHelper listener) { synchronized (mDrmLock) { - mOnDrmConfigListener = listener; + mOnDrmConfigHelper = listener; } // synchronized } - private OnDrmConfigListener mOnDrmConfigListener; + private OnDrmConfigHelper mOnDrmConfigHelper; /** * Interface definition of a callback to be invoked when the @@ -3946,7 +3948,7 @@ public class MediaPlayer extends PlayerBase * Called to indicate DRM info is available * * @param mp the {@code MediaPlayer} associated with this callback - * @param drmInfo DRM info of the source including PSSH, mimes, and subset + * @param drmInfo DRM info of the source including PSSH, and subset * of crypto schemes supported by this device */ public void onDrmInfo(MediaPlayer mp, DrmInfo drmInfo); @@ -3982,6 +3984,41 @@ public class MediaPlayer extends PlayerBase private OnDrmInfoHandlerDelegate mOnDrmInfoHandlerDelegate; + + /** + * The status codes for {@link OnDrmPreparedListener#onDrmPrepared} listener. + * <p> + * + * DRM preparation has succeeded. + */ + public static final int PREPARE_DRM_STATUS_SUCCESS = 0; + + /** + * The device required DRM provisioning but couldn't reach the provisioning server. + */ + public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; + + /** + * The device required DRM provisioning but the provisioning server denied the request. + */ + public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; + + /** + * The DRM preparation has failed . + */ + public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; + + + /** @hide */ + @IntDef({ + PREPARE_DRM_STATUS_SUCCESS, + PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR, + PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR, + PREPARE_DRM_STATUS_PREPARATION_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PrepareDrmStatusCode {} + /** * Interface definition of a callback to notify the app when the * DRM is ready for key request/response @@ -3992,9 +4029,13 @@ public class MediaPlayer extends PlayerBase * Called to notify the app that prepareDrm is finished and ready for key request/response * * @param mp the {@code MediaPlayer} associated with this callback - * @param success the result of DRM preparation + * @param status the result of DRM preparation which can be + * {@link #PREPARE_DRM_STATUS_SUCCESS}, + * {@link #PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR}, + * {@link #PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR}, or + * {@link #PREPARE_DRM_STATUS_PREPARATION_ERROR}. */ - public void onDrmPrepared(MediaPlayer mp, boolean success); + public void onDrmPrepared(MediaPlayer mp, @PrepareDrmStatusCode int status); } /** @@ -4038,30 +4079,28 @@ public class MediaPlayer extends PlayerBase mOnDrmInfoListener = listener; // find the looper for our new event handler - Looper looper = null; if (handler != null) { - looper = handler.getLooper(); - } - - // construct the event handler with this looper - if (looper != null) { - // implement the event handler delegate - mHandler = new Handler(looper) { - public void handleMessage(Message msg) { - DrmInfo drmInfo = (DrmInfo)msg.obj; - mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo); - } - }; + mHandler = handler; + } else { + // handler == null + // Will let OnDrmInfoListener be called in mEventHandler similar to other + // legacy notifications. This is because MEDIA_DRM_INFO's notification has to be + // sent before MEDIA_PREPARED's (i.e., in the same order they are issued by + // mediaserver). As a result, the callback has to be called directly by + // EventHandler.handleMessage similar to onPrepared. } } void notifyClient(DrmInfo drmInfo) { - if ( mHandler != null ) { - Message msg = new Message(); // no message type needed - msg.obj = drmInfo; - mHandler.sendMessage(msg); + if (mHandler != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo); + } + }); } - else { // no handler: direct call + else { // no handler: direct call by mEventHandler mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo); } } @@ -4078,31 +4117,26 @@ public class MediaPlayer extends PlayerBase mOnDrmPreparedListener = listener; // find the looper for our new event handler - Looper looper = null; if (handler != null) { - looper = handler.getLooper(); - } - - // construct the event handler with this looper - if (looper != null) { - // implement the event handler delegate - mHandler = new Handler(looper) { - public void handleMessage(Message msg) { - boolean success = (msg.arg1 == 0) ? false : true; - mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success); - } - }; + mHandler = handler; + } else if (mEventHandler != null) { + // Otherwise, use mEventHandler + mHandler = mEventHandler; + } else { + Log.e(TAG, "OnDrmPreparedHandlerDelegate: Unexpected null mEventHandler"); } } - void notifyClient(boolean success) { - if ( mHandler != null ) { - Message msg = new Message(); // no message type needed - msg.arg1 = success ? 1 : 0; - mHandler.sendMessage(msg); - } - else { // no handler: direct call - mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success); + void notifyClient(int status) { + if (mHandler != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, status); + } + }); + } else { + Log.e(TAG, "OnDrmPreparedHandlerDelegate:notifyClient: Unexpected null mHandler"); } } } @@ -4137,7 +4171,7 @@ public class MediaPlayer extends PlayerBase /** * Prepares the DRM for the current source * <p> - * If {@code OnDrmConfigListener} is registered, it will be called half-way into + * If {@code OnDrmConfigHelper} is registered, it will be called during * preparation to allow configuration of the DRM properties before opening the * DRM session. Note that the callback is called synchronously in the thread that called * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString} @@ -4148,9 +4182,9 @@ public class MediaPlayer extends PlayerBase * complete depending on the network connectivity. * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking * mode by launching the provisioning in the background and returning. The listener - * will be called when provisioning and preperation has finished. If a + * will be called when provisioning and preparation has finished. If a * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning - * and preperation has finished, i.e., runs in blocking mode. + * and preparation has finished, i.e., runs in blocking mode. * <p> * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM * session being ready. The application should not make any assumption about its call @@ -4158,18 +4192,23 @@ public class MediaPlayer extends PlayerBase * execute the listener (unless the listener is registered with a handler thread). * <p> * - * @param uuid The UUID of the crypto scheme. + * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved + * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}. * - * @throws IllegalStateException if called before prepare(), or there exists a Drm already - * @throws UnsupportedSchemeException if the crypto scheme is not supported - * @throws ResourceBusyException if required DRM resources are in use - * @throws ProvisioningErrorException if provisioning is required but an attempt failed + * @throws IllegalStateException if called before prepare(), or the DRM was + * prepared already + * @throws UnsupportedSchemeException if the crypto scheme is not supported + * @throws ResourceBusyException if required DRM resources are in use + * @throws ProvisioningNetworkErrorException if provisioning is required but failed due to a + * network error + * @throws ProvisioningServerErrorException if provisioning is required but failed due to + * the request denied by the provisioning server */ public void prepareDrm(@NonNull UUID uuid) - throws UnsupportedSchemeException, - ResourceBusyException, ProvisioningErrorException + throws UnsupportedSchemeException, ResourceBusyException, + ProvisioningNetworkErrorException, ProvisioningServerErrorException { - Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigListener: " + mOnDrmConfigListener); + Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper); boolean allDoneWithoutProvisioning = false; // get a snapshot as we'll use them outside the lock @@ -4177,7 +4216,7 @@ public class MediaPlayer extends PlayerBase synchronized (mDrmLock) { - // only allowing if tied to a protected source; might releax for releasing offline keys + // only allowing if tied to a protected source; might relax for releasing offline keys if (mDrmInfo == null) { final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " + "DRM info be retrieved before this call."; @@ -4226,8 +4265,8 @@ public class MediaPlayer extends PlayerBase // call the callback outside the lock - if (mOnDrmConfigListener != null) { - mOnDrmConfigListener.onDrmConfig(this); + if (mOnDrmConfigHelper != null) { + mOnDrmConfigHelper.onDrmConfig(this); } synchronized (mDrmLock) { @@ -4251,15 +4290,33 @@ public class MediaPlayer extends PlayerBase Log.w(TAG, "prepareDrm: NotProvisionedException"); // handle provisioning internally; it'll reset mPrepareDrmInProgress - boolean result = HandleProvisioninig(uuid); + int result = HandleProvisioninig(uuid); // if blocking mode, we're already done; // if non-blocking mode, we attempted to launch background provisioning - if (result == false) { - final String msg = "prepareDrm: Provisioning was required but failed."; - Log.e(TAG, msg); + if (result != PREPARE_DRM_STATUS_SUCCESS) { earlyExit = true; - throw new ProvisioningErrorException(msg); + String msg; + + switch (result) { + case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR: + msg = "prepareDrm: Provisioning was required but failed " + + "due to a network error."; + Log.e(TAG, msg); + throw new ProvisioningNetworkErrorException(msg); + + case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR: + msg = "prepareDrm: Provisioning was required but the request " + + "was denied by the server."; + Log.e(TAG, msg); + throw new ProvisioningServerErrorException(msg); + + case PREPARE_DRM_STATUS_PREPARATION_ERROR: + default: // default for safeguard + msg = "prepareDrm: Post-provisioning preparation failed."; + Log.e(TAG, msg); + throw new IllegalStateException(msg); + } } // nothing else to do; // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup @@ -4281,7 +4338,7 @@ public class MediaPlayer extends PlayerBase // if finished successfully without provisioning, call the callback outside the lock if (allDoneWithoutProvisioning) { if (onDrmPreparedHandlerDelegate != null) - onDrmPreparedHandlerDelegate.notifyClient(true /*success*/); + onDrmPreparedHandlerDelegate.notifyClient(PREPARE_DRM_STATUS_SUCCESS); } } @@ -4291,6 +4348,10 @@ public class MediaPlayer extends PlayerBase /** * Releases the DRM session + * <p> + * The player has to have an active DRM session and be in stopped, or prepared + * state before this call is made. + * A {@code reset()} call will release the DRM session implicitly. * * @throws NoDrmSchemeException if there is no active DRM session to release */ @@ -4307,7 +4368,7 @@ public class MediaPlayer extends PlayerBase try { // we don't have the player's state in this layer. The below call raises - // exception if we're in a non-stopped/idle state. + // exception if we're in a non-stopped/prepared state. // for cleaning native/mediaserver crypto object _releaseDrm(); @@ -4316,9 +4377,11 @@ public class MediaPlayer extends PlayerBase cleanDrmObj(); mActiveDrmScheme = false; - } catch (Exception e) { + } catch (IllegalStateException e) { Log.w(TAG, "releaseDrm: Exception ", e); - throw e; + throw new IllegalStateException("releaseDrm: The player is not in a valid state."); + } catch (Exception e) { + Log.e(TAG, "releaseDrm: Exception ", e); } } // synchronized } @@ -4337,21 +4400,23 @@ public class MediaPlayer extends PlayerBase * it should deliver to the response to the DRM engine plugin using the method * {@link #provideKeyResponse}. * - * @param scope may be a container-specific initialization data or a keySetId, - * depending on the specified keyType. - * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, scope should be set to - * the container-specific initialization data. Its meaning is interpreted based on the - * mime type provided in the mimeType parameter. It could contain, for example, - * the content ID, key ID or other data obtained from the content metadata that is - * required in generating the key request. - * When the keyType is KEY_TYPE_RELEASE, scope should be set to the keySetId of - * the keys being released. + * @param keySetId is the key-set identifier of the offline keys being released when keyType is + * {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when + * keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. + * + * @param initData is the container-specific initialization data when the keyType is + * {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is + * interpreted based on the mime type provided in the mimeType parameter. It could + * contain, for example, the content ID, key ID or other data obtained from the content + * metadata that is required in generating the key request. + * When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null. * * @param mimeType identifies the mime type of the content * - * @param keyType specifes the type of the request. The request may be to acquire - * keys for streaming or offline content, or to release previously acquired - * keys, which are identified by a keySetId. + * @param keyType specifies the type of the request. The request may be to acquire + * keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content + * {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired + * keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId. * * @param optionalParameters are included in the key request message to * allow a client application to provide additional message parameters to the server. @@ -4360,12 +4425,13 @@ public class MediaPlayer extends PlayerBase * @throws NoDrmSchemeException if there is no active DRM session */ @NonNull - public MediaDrm.KeyRequest getKeyRequest(@NonNull byte[] scope, @Nullable String mimeType, - @MediaDrm.KeyType int keyType, @Nullable Map<String, String> optionalParameters) + public MediaDrm.KeyRequest getKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData, + @Nullable String mimeType, @MediaDrm.KeyType int keyType, + @Nullable Map<String, String> optionalParameters) throws NoDrmSchemeException { Log.v(TAG, "getKeyRequest: " + - " scope: " + scope + " mimeType: " + mimeType + + " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType + " keyType: " + keyType + " optionalParameters: " + optionalParameters); synchronized (mDrmLock) { @@ -4375,20 +4441,16 @@ public class MediaPlayer extends PlayerBase } try { - byte[] scopeOut = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? - mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE - scope; // keySetId for KEY_TYPE_RELEASE - - byte[] initData = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? - scope : // initData for KEY_TYPE_STREAMING/OFFLINE - null; // not used for KEY_TYPE_RELEASE + byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? + mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE + keySetId; // keySetId for KEY_TYPE_RELEASE HashMap<String, String> hmapOptionalParameters = (optionalParameters != null) ? new HashMap<String, String>(optionalParameters) : null; - MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scopeOut, initData, mimeType, + MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scope, initData, mimeType, keyType, hmapOptionalParameters); Log.v(TAG, "getKeyRequest: --> request: " + request); @@ -4499,8 +4561,8 @@ public class MediaPlayer extends PlayerBase * @param propertyName the property name * * Standard fields names are: - * {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION}, - * {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS} + * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION}, + * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS} */ @NonNull public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName) @@ -4537,8 +4599,8 @@ public class MediaPlayer extends PlayerBase * @param value the property value * * Standard fields names are: - * {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION}, - * {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS} + * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION}, + * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS} */ public void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName, @NonNull String value) @@ -4565,8 +4627,6 @@ public class MediaPlayer extends PlayerBase public static final class DrmInfo { private Map<UUID, byte[]> mapPssh; private UUID[] supportedSchemes; - // TODO: Won't need this in final release. Only keeping it for the existing test app. - private String[] mimes; public Map<UUID, byte[]> getPssh() { return mapPssh; @@ -4574,15 +4634,10 @@ public class MediaPlayer extends PlayerBase public UUID[] getSupportedSchemes() { return supportedSchemes; } - // TODO: Won't need this in final release. Only keeping it for the existing test app. - public String[] getMimes() { - return mimes; - } - private DrmInfo(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes, String[] Mimes) { + private DrmInfo(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes) { mapPssh = Pssh; supportedSchemes = SupportedSchemes; - mimes = Mimes; } private DrmInfo(Parcel parcel) { @@ -4608,18 +4663,12 @@ public class MediaPlayer extends PlayerBase supportedSchemes[i]); } - // TODO: Won't need this in final release. Only keeping it for the test app. - mimes = parcel.readStringArray(); - int mimeCount = mimes.length; - Log.v(TAG, "DrmInfo() mime: " + Arrays.toString(mimes)); - Log.v(TAG, "DrmInfo() Parcel psshsize: " + psshsize + - " supportedDRMsCount: " + supportedDRMsCount + - " mimeCount: " + mimeCount); + " supportedDRMsCount: " + supportedDRMsCount); } private DrmInfo makeCopy() { - return new DrmInfo(this.mapPssh, this.supportedSchemes, this.mimes); + return new DrmInfo(this.mapPssh, this.supportedSchemes); } private String arrToHex(byte[] bytes) { @@ -4714,11 +4763,22 @@ public class MediaPlayer extends PlayerBase /** * Thrown when the device requires DRM provisioning but the provisioning attempt has - * failed (for example: network timeout, provisioning server error). + * failed due to a network error (Internet reachability, timeout, etc.). * Extends MediaDrm.MediaDrmException */ - public static final class ProvisioningErrorException extends MediaDrmException { - public ProvisioningErrorException(String detailMessage) { + public static final class ProvisioningNetworkErrorException extends MediaDrmException { + public ProvisioningNetworkErrorException(String detailMessage) { + super(detailMessage); + } + } + + /** + * Thrown when the device requires DRM provisioning but the provisioning attempt has + * failed due to the provisioning server denying the request. + * Extends MediaDrm.MediaDrmException + */ + public static final class ProvisioningServerErrorException extends MediaDrmException { + public ProvisioningServerErrorException(String detailMessage) { super(detailMessage); } } @@ -4770,14 +4830,13 @@ public class MediaPlayer extends PlayerBase private UUID uuid; private String urlStr; - private byte[] response; private Object drmLock; private OnDrmPreparedHandlerDelegate onDrmPreparedHandlerDelegate; private MediaPlayer mediaPlayer; - private boolean succeeded; + private int status; private boolean finished; - public boolean succeeded() { - return succeeded; + public int status() { + return status; } public ProvisioningThread initialize(MediaDrm.ProvisionRequest request, @@ -4790,12 +4849,15 @@ public class MediaPlayer extends PlayerBase urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData()); this.uuid = uuid; + status = PREPARE_DRM_STATUS_PREPARATION_ERROR; + Log.v(TAG, "HandleProvisioninig: Thread is initialised url: " + urlStr); return this; } public void run() { + byte[] response = null; boolean provisioningSucceeded = false; try { URL url = new URL(urlStr); @@ -4813,11 +4875,13 @@ public class MediaPlayer extends PlayerBase Log.v(TAG, "HandleProvisioninig: Thread run: response " + response.length + " " + response); } catch (Exception e) { + status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR; Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url); } finally { connection.disconnect(); } } catch (Exception e) { + status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR; Log.w(TAG, "HandleProvisioninig: Thread run: openConnection " + e); } @@ -4828,12 +4892,15 @@ public class MediaPlayer extends PlayerBase "provideProvisionResponse SUCCEEDED!"); provisioningSucceeded = true; - } catch (Exception e) { + } catch (Exception e) { + status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR; Log.w(TAG, "HandleProvisioninig: Thread run: " + "provideProvisionResponse " + e); } } + boolean succeeded = false; + // non-blocking mode needs the lock if (onDrmPreparedHandlerDelegate != null) { @@ -4841,6 +4908,9 @@ public class MediaPlayer extends PlayerBase // continuing with prepareDrm if (provisioningSucceeded) { succeeded = mediaPlayer.resumePrepareDrm(uuid); + status = (succeeded) ? + PREPARE_DRM_STATUS_SUCCESS : + PREPARE_DRM_STATUS_PREPARATION_ERROR; } mediaPlayer.mDrmProvisioningInProgress = false; mediaPlayer.mPrepareDrmInProgress = false; @@ -4850,12 +4920,15 @@ public class MediaPlayer extends PlayerBase } // synchronized // calling the callback outside the lock - onDrmPreparedHandlerDelegate.notifyClient(succeeded); + onDrmPreparedHandlerDelegate.notifyClient(status); } else { // blocking mode already has the lock // continuing with prepareDrm if (provisioningSucceeded) { succeeded = mediaPlayer.resumePrepareDrm(uuid); + status = (succeeded) ? + PREPARE_DRM_STATUS_SUCCESS : + PREPARE_DRM_STATUS_PREPARATION_ERROR; } mediaPlayer.mDrmProvisioningInProgress = false; mediaPlayer.mPrepareDrmInProgress = false; @@ -4869,19 +4942,19 @@ public class MediaPlayer extends PlayerBase } // ProvisioningThread - private boolean HandleProvisioninig(UUID uuid) + private int HandleProvisioninig(UUID uuid) { // the lock is already held by the caller if (mDrmProvisioningInProgress) { Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress"); - return false; + return PREPARE_DRM_STATUS_PREPARATION_ERROR; } MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest(); if (provReq == null) { Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null."); - return false; + return PREPARE_DRM_STATUS_PREPARATION_ERROR; } Log.v(TAG, "HandleProvisioninig provReq " + @@ -4893,11 +4966,11 @@ public class MediaPlayer extends PlayerBase mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this); mDrmProvisioningThread.start(); - boolean result = false; + int result; - // non-blocking + // non-blocking: this is not the final result if (mOnDrmPreparedHandlerDelegate != null) { - result = true; + result = PREPARE_DRM_STATUS_SUCCESS; } else { // if blocking mode, wait till provisioning is done try { @@ -4905,7 +4978,7 @@ public class MediaPlayer extends PlayerBase } catch (Exception e) { Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e); } - result = mDrmProvisioningThread.succeeded(); + result = mDrmProvisioningThread.status(); // no longer need the thread mDrmProvisioningThread = null; } diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index 246bd2bc7ce0..5beb41253d48 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -314,8 +314,8 @@ public class DeviceDiscoveryService extends Service { } class DevicesAdapter extends ArrayAdapter<DeviceFilterPair> { - //TODO wifi icon private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth); + private Drawable WIFI_ICON = icon(com.android.internal.R.drawable.ic_wifi_signal_3); private Drawable icon(int drawableRes) { Drawable icon = getResources().getDrawable(drawableRes, null); @@ -345,6 +345,11 @@ public class DeviceDiscoveryService extends Service { device.equals(mSelectedDevice) ? Color.GRAY : Color.TRANSPARENT); + textView.setCompoundDrawablesWithIntrinsicBounds( + device.device instanceof android.net.wifi.ScanResult + ? WIFI_ICON + : BLUETOOTH_ICON, + null, null, null); textView.setOnClickListener((view) -> { mSelectedDevice = device; notifyDataSetChanged(); @@ -357,8 +362,6 @@ public class DeviceDiscoveryService extends Service { textView.setTextColor(Color.BLACK); final int padding = DeviceChooserActivity.getPadding(getResources()); textView.setPadding(padding, padding, padding, padding); - textView.setCompoundDrawablesWithIntrinsicBounds( - BLUETOOTH_ICON, null, null, null); textView.setCompoundDrawablePadding(padding); return textView; } diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 10f3b6341e42..c10970467383 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -46,6 +46,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.text.format.Formatter; +import android.util.IconDrawableFactory; import android.util.Log; import android.util.SparseArray; @@ -95,6 +96,7 @@ public class ApplicationsState { final Context mContext; final PackageManager mPm; + final IconDrawableFactory mDrawableFactory; final IPackageManager mIpm; final UserManager mUm; final StorageStatsManager mStats; @@ -132,6 +134,7 @@ public class ApplicationsState { private ApplicationsState(Application app) { mContext = app; mPm = mContext.getPackageManager(); + mDrawableFactory = IconDrawableFactory.newInstance(mContext); mIpm = AppGlobals.getPackageManager(); mUm = mContext.getSystemService(UserManager.class); mStats = mContext.getSystemService(StorageStatsManager.class); @@ -327,7 +330,7 @@ public class ApplicationsState { return; } synchronized (entry) { - entry.ensureIconLocked(mContext, mPm); + entry.ensureIconLocked(mContext, mDrawableFactory); } } @@ -943,7 +946,7 @@ public class ApplicationsState { AppEntry entry = mAppEntries.get(i); if (entry.icon == null || !entry.mounted) { synchronized (entry) { - if (entry.ensureIconLocked(mContext, mPm)) { + if (entry.ensureIconLocked(mContext, mDrawableFactory)) { if (!mRunning) { mRunning = true; Message m = mMainHandler.obtainMessage( @@ -1266,10 +1269,10 @@ public class ApplicationsState { } } - boolean ensureIconLocked(Context context, PackageManager pm) { + boolean ensureIconLocked(Context context, IconDrawableFactory drawableFactory) { if (this.icon == null) { if (this.apkFile.exists()) { - this.icon = getBadgedIcon(pm); + this.icon = drawableFactory.getBadgedIcon(info); return true; } else { this.mounted = false; @@ -1281,19 +1284,13 @@ public class ApplicationsState { // its icon. if (this.apkFile.exists()) { this.mounted = true; - this.icon = getBadgedIcon(pm); + this.icon = drawableFactory.getBadgedIcon(info); return true; } } return false; } - private Drawable getBadgedIcon(PackageManager pm) { - // Do badging ourself so that it comes from the user of the app not the current user. - return pm.getUserBadgedIcon(pm.loadUnbadgedItemIcon(info, info), - new UserHandle(UserHandle.getUserId(info.uid))); - } - public String getVersion(Context context) { try { return context.getPackageManager().getPackageInfo(info.packageName, 0).versionName; diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java index 231fc695d344..3f826cc00b8b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java +++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java @@ -27,6 +27,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.util.IconDrawableFactory; import android.util.Log; import java.util.ArrayList; @@ -48,10 +49,12 @@ public class RecentLocationApps { private final PackageManager mPackageManager; private final Context mContext; + private final IconDrawableFactory mDrawableFactory; public RecentLocationApps(Context context) { mContext = context; mPackageManager = context.getPackageManager(); + mDrawableFactory = IconDrawableFactory.newInstance(context); } /** @@ -146,8 +149,7 @@ public class RecentLocationApps { } final UserHandle userHandle = new UserHandle(userId); - Drawable appIcon = mPackageManager.getApplicationIcon(appInfo); - Drawable icon = mPackageManager.getUserBadgedIcon(appIcon, userHandle); + Drawable icon = mDrawableFactory.getBadgedIcon(appInfo, userId); CharSequence appLabel = mPackageManager.getApplicationLabel(appInfo); CharSequence badgedAppLabel = mPackageManager.getUserBadgedLabel(appLabel, userHandle); if (appLabel.toString().contentEquals(badgedAppLabel)) { diff --git a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml b/packages/SystemUI/res/drawable/ic_pause_white.xml index 5b65f100490c..5b65f100490c 100644 --- a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_pause_white.xml diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white.xml index ddc9e8dd17a0..ddc9e8dd17a0 100644 --- a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_play_arrow_white.xml diff --git a/packages/SystemUI/res/drawable/ic_skip_next_white.xml b/packages/SystemUI/res/drawable/ic_skip_next_white.xml new file mode 100644 index 000000000000..040c7e642241 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_skip_next_white.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +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" + android:viewportHeight="24"> + + <path + android:fillColor="#FFFFFF" + android:pathData="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z" /> + <path + android:pathData="M0 0h24v24H0z" /> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_skip_previous_white.xml b/packages/SystemUI/res/drawable/ic_skip_previous_white.xml new file mode 100644 index 000000000000..b9b94b73a00f --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_skip_previous_white.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +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" + android:viewportHeight="24"> + + <path + android:fillColor="#FFFFFF" + android:pathData="M6 6h2v12H6zm3.5 6l8.5 6V6z" /> + <path + android:pathData="M0 0h24v24H0z" /> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml index c6bcd32901dd..61ac6f6991ff 100644 --- a/packages/SystemUI/res/layout/tv_pip_controls.xml +++ b/packages/SystemUI/res/layout/tv_pip_controls.xml @@ -40,7 +40,7 @@ android:layout_width="100dp" android:layout_height="wrap_content" android:layout_marginStart="-50dp" - android:src="@drawable/ic_pause_white_24dp" + android:src="@drawable/ic_pause_white" android:text="@string/pip_pause" android:visibility="gone" /> </merge> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 33b1dd40e471..b87da27ea632 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -376,13 +376,13 @@ <string name="accessibility_no_sim">No SIM.</string> <!-- Content description of the cell data. [CHAR LIMIT=NONE] --> - <string name="accessibility_cell_data">Cellular Data</string> + <string name="accessibility_cell_data">Mobile Data</string> <!-- Content description of the cell data being enabled. [CHAR LIMIT=NONE] --> - <string name="accessibility_cell_data_on">Cellular Data On</string> + <string name="accessibility_cell_data_on">Mobile Data On</string> <!-- Content description of the cell data being disabled. [CHAR LIMIT=NONE] --> - <string name="accessibility_cell_data_off">Cellular Data Off</string> + <string name="accessibility_cell_data_off">Mobile Data Off</string> <!-- Content description of the bluetooth tethering icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_bluetooth_tether">Bluetooth tethering.</string> @@ -574,11 +574,11 @@ <!-- Title of dialog shown when 4G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] --> <string name="data_usage_disabled_dialog_4g_title">4G data is paused</string> <!-- Title of dialog shown when mobile data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] --> - <string name="data_usage_disabled_dialog_mobile_title">Cellular data is paused</string> + <string name="data_usage_disabled_dialog_mobile_title">Mobile data is paused</string> <!-- Title of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] --> <string name="data_usage_disabled_dialog_title">Data is paused</string> <!-- Body of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=NONE] --> - <string name="data_usage_disabled_dialog">The data limit you set has been reached. You are no longer using cellular data.\n\nIf you resume, charges may apply for data usage.</string> + <string name="data_usage_disabled_dialog">The data limit you set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage.</string> <!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] --> <string name="data_usage_disabled_dialog_enable">Resume</string> @@ -749,7 +749,7 @@ <!-- QuickSettings: Flashlight [CHAR LIMIT=NONE] --> <string name="quick_settings_flashlight_label">Flashlight</string> <!-- QuickSettings: Cellular detail panel title [CHAR LIMIT=NONE] --> - <string name="quick_settings_cellular_detail_title">Cellular data</string> + <string name="quick_settings_cellular_detail_title">Mobile data</string> <!-- QuickSettings: Cellular detail panel, data usage title [CHAR LIMIT=NONE] --> <string name="quick_settings_cellular_detail_data_usage">Data usage</string> <!-- QuickSettings: Cellular detail panel, remaining data title [CHAR LIMIT=NONE] --> @@ -1897,6 +1897,18 @@ <!-- PiP minimize description. [CHAR LIMIT=NONE] --> <string name="pip_minimize_description" translatable="false">Drag or fling the PIP to the edges of the screen to minimize it.</string> + <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] --> + <string name="pip_play">Play</string> + + <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] --> + <string name="pip_pause">Pause</string> + + <!-- Button to skip to the next media on picture-in-picture (PIP) [CHAR LIMIT=30] --> + <string name="pip_skip_to_next">Skip to next</string> + + <!-- Button to skip to the prev media on picture-in-picture (PIP) [CHAR LIMIT=30] --> + <string name="pip_skip_to_prev">Skip to previous</string> + <!-- Tuner string --> <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string> <!-- Tuner string --> diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml index 41626fcb0a49..e578068163d7 100644 --- a/packages/SystemUI/res/values/strings_tv.xml +++ b/packages/SystemUI/res/values/strings_tv.xml @@ -23,8 +23,4 @@ <string name="pip_close">Close PIP</string> <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] --> <string name="pip_fullscreen">Full screen</string> - <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] --> - <string name="pip_play">Play</string> - <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] --> - <string name="pip_pause">Pause</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java index 86bb0deff067..4b3cdfbcd71c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java @@ -39,7 +39,8 @@ public class PipDismissViewController { // This delay controls how long to wait before we show the target when the user first moves // the PIP, to prevent the target from animating if the user just wants to fling the PIP private static final int SHOW_TARGET_DELAY = 100; - private static final int SHOW_TARGET_DURATION = 200; + private static final int SHOW_TARGET_DURATION = 350; + private static final int HIDE_TARGET_DURATION = 225; private Context mContext; private WindowManager mWindowManager; @@ -96,7 +97,7 @@ public class PipDismissViewController { public void showDismissTarget() { mDismissView.animate() .alpha(1f) - .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN) + .setInterpolator(Interpolators.LINEAR) .setStartDelay(SHOW_TARGET_DELAY) .setDuration(SHOW_TARGET_DURATION) .start(); @@ -109,9 +110,9 @@ public class PipDismissViewController { if (mDismissView != null) { mDismissView.animate() .alpha(0f) - .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN) + .setInterpolator(Interpolators.LINEAR) .setStartDelay(0) - .setDuration(SHOW_TARGET_DURATION) + .setDuration(HIDE_TARGET_DURATION) .withEndAction(new Runnable() { @Override public void run() { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java index 3a4caa9a1e88..62ec09be2f51 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java @@ -48,6 +48,8 @@ public class PipMediaController { private static final String ACTION_PLAY = "com.android.systemui.pip.phone.PLAY"; private static final String ACTION_PAUSE = "com.android.systemui.pip.phone.PAUSE"; + private static final String ACTION_NEXT = "com.android.systemui.pip.phone.NEXT"; + private static final String ACTION_PREV = "com.android.systemui.pip.phone.PREV"; /** * A listener interface to receive notification on changes to the media actions. @@ -67,6 +69,8 @@ public class PipMediaController { private RemoteAction mPauseAction; private RemoteAction mPlayAction; + private RemoteAction mNextAction; + private RemoteAction mPrevAction; private BroadcastReceiver mPlayPauseActionReceiver = new BroadcastReceiver() { @Override @@ -76,6 +80,10 @@ public class PipMediaController { mMediaController.getTransportControls().play(); } else if (action.equals(ACTION_PAUSE)) { mMediaController.getTransportControls().pause(); + } else if (action.equals(ACTION_NEXT)) { + mMediaController.getTransportControls().skipToNext(); + } else if (action.equals(ACTION_PREV)) { + mMediaController.getTransportControls().skipToPrevious(); } } }; @@ -95,6 +103,8 @@ public class PipMediaController { IntentFilter mediaControlFilter = new IntentFilter(); mediaControlFilter.addAction(ACTION_PLAY); mediaControlFilter.addAction(ACTION_PAUSE); + mediaControlFilter.addAction(ACTION_NEXT); + mediaControlFilter.addAction(ACTION_PREV); mContext.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter); createMediaActions(); @@ -143,11 +153,21 @@ public class PipMediaController { int state = mMediaController.getPlaybackState().getState(); boolean isPlaying = MediaSession.isActiveState(state); long actions = mMediaController.getPlaybackState().getActions(); + + // Prev action + mPrevAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0); + mediaActions.add(mPrevAction); + + // Play/pause action if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) { mediaActions.add(mPlayAction); } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) { mediaActions.add(mPauseAction); } + + // Next action + mNextAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0); + mediaActions.add(mNextAction); return mediaActions; } @@ -157,15 +177,27 @@ public class PipMediaController { private void createMediaActions() { String pauseDescription = mContext.getString(R.string.pip_pause); mPauseAction = new RemoteAction(Icon.createWithResource(mContext, - R.drawable.ic_pause_white_24dp), pauseDescription, pauseDescription, + R.drawable.ic_pause_white), pauseDescription, pauseDescription, PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PAUSE), FLAG_UPDATE_CURRENT)); String playDescription = mContext.getString(R.string.pip_play); mPlayAction = new RemoteAction(Icon.createWithResource(mContext, - R.drawable.ic_play_arrow_white_24dp), playDescription, playDescription, + R.drawable.ic_play_arrow_white), playDescription, playDescription, PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PLAY), FLAG_UPDATE_CURRENT)); + + String nextDescription = mContext.getString(R.string.pip_skip_to_next); + mNextAction = new RemoteAction(Icon.createWithResource(mContext, + R.drawable.ic_skip_next_white), nextDescription, nextDescription, + PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NEXT), + FLAG_UPDATE_CURRENT)); + + String prevDescription = mContext.getString(R.string.pip_skip_to_prev); + mPrevAction = new RemoteAction(Icon.createWithResource(mContext, + R.drawable.ic_skip_previous_white), prevDescription, prevDescription, + PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PREV), + FLAG_UPDATE_CURRENT)); } /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 982b8085b216..79ac8160c095 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -412,16 +412,26 @@ public class PipMenuActivity extends Activity { } else { actionsContainer.setVisibility(View.VISIBLE); if (mActionsGroup != null) { - mActionsGroup.removeAllViews(); + // Hide extra views + for (int i = mActions.size(); i < mActionsGroup.getChildCount(); i++) { + mActionsGroup.getChildAt(i).setVisibility(View.GONE); + } + // Add needed views + final LayoutInflater inflater = LayoutInflater.from(this); + while (mActionsGroup.getChildCount() < mActions.size()) { + final ImageView actionView = (ImageView) inflater.inflate( + R.layout.pip_menu_action, mActionsGroup, false); + mActionsGroup.addView(actionView); + } // Recreate the layout final boolean isLandscapePip = stackBounds != null && (stackBounds.width() > stackBounds.height()); - final LayoutInflater inflater = LayoutInflater.from(this); for (int i = 0; i < mActions.size(); i++) { final RemoteAction action = mActions.get(i); - final ImageView actionView = (ImageView) inflater.inflate( - R.layout.pip_menu_action, mActionsGroup, false); + final ImageView actionView = (ImageView) mActionsGroup.getChildAt(i); + + // TODO: Check if the action drawable has changed before we reload it action.getIcon().loadDrawableAsync(this, d -> { d.setTint(Color.WHITE); actionView.setImageDrawable(d); @@ -439,12 +449,11 @@ public class PipMenuActivity extends Activity { actionView.setAlpha(DISABLED_ACTION_ALPHA); actionView.setEnabled(false); } - if (isLandscapePip && i > 0) { - LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) - actionView.getLayoutParams(); - lp.leftMargin = mBetweenActionPaddingLand; - } - mActionsGroup.addView(actionView); + + // Update the margin between actions + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) + actionView.getLayoutParams(); + lp.leftMargin = (isLandscapePip && i > 0) ? mBetweenActionPaddingLand : 0; } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index fbf7ff21b0ce..3223f9fd52b1 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -63,7 +63,7 @@ public class PipTouchHandler implements TunerService.Tunable { private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0; private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1; - private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 200; + private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 225; // Allow dragging the PIP to a location to close it private static final boolean ENABLE_DISMISS_DRAG_TO_EDGE = true; diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java index 4c81907c35f7..acea3b6b12ad 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java @@ -186,10 +186,10 @@ public class PipControlsView extends LinearLayout { } else { mPlayPauseButtonView.setVisibility(View.VISIBLE); if (state == PipManager.PLAYBACK_STATE_PLAYING) { - mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white_24dp); + mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white); mPlayPauseButtonView.setText(R.string.pip_pause); } else { - mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white_24dp); + mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white); mPlayPauseButtonView.setText(R.string.pip_play); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index ccebd7ceec32..429ace62ad16 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -65,7 +65,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.ArraySet; -import android.util.LauncherIcons; +import android.util.IconDrawableFactory; import android.util.Log; import android.util.MutableBoolean; import android.view.Display; @@ -121,6 +121,7 @@ public class SystemServicesProxy { ActivityManager mAm; IActivityManager mIam; PackageManager mPm; + IconDrawableFactory mDrawableFactory; IPackageManager mIpm; AssistUtils mAssistUtils; WindowManager mWm; @@ -139,7 +140,6 @@ public class SystemServicesProxy { int mDummyThumbnailHeight; Paint mBgProtectionPaint; Canvas mBgProtectionCanvas; - LauncherIcons mLauncherIcons; private final Handler mHandler = new H(); @@ -258,6 +258,7 @@ public class SystemServicesProxy { mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mIam = ActivityManager.getService(); mPm = context.getPackageManager(); + mDrawableFactory = IconDrawableFactory.newInstance(context); mIpm = AppGlobals.getPackageManager(); mAssistUtils = new AssistUtils(context); mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); @@ -296,8 +297,6 @@ public class SystemServicesProxy { Collections.addAll(sRecentsBlacklist, res.getStringArray(R.array.recents_blacklist_array)); - - mLauncherIcons = new LauncherIcons(context); } /** @@ -808,13 +807,19 @@ public class SystemServicesProxy { * Returns the content description for a given task, badging it if necessary. The content * description joins the app and activity labels. */ - public String getBadgedContentDescription(ActivityInfo info, int userId, Resources res) { + public String getBadgedContentDescription(ActivityInfo info, int userId, + ActivityManager.TaskDescription td, Resources res) { // If we are mocking, then return a mock label if (RecentsDebugFlags.Static.EnableMockTasks) { return "Recent Task Content Description: " + userId; } - String activityLabel = info.loadLabel(mPm).toString(); + String activityLabel; + if (td != null && td.getLabel() != null) { + activityLabel = td.getLabel(); + } else { + activityLabel = info.loadLabel(mPm).toString(); + } String applicationLabel = info.applicationInfo.loadLabel(mPm).toString(); String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId); return applicationLabel.equals(activityLabel) ? badgedApplicationLabel @@ -834,8 +839,7 @@ public class SystemServicesProxy { return new ColorDrawable(0xFF666666); } - Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(info.loadIcon(mPm)); - return getBadgedIcon(icon, userId); + return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId); } /** @@ -850,8 +854,7 @@ public class SystemServicesProxy { return new ColorDrawable(0xFF666666); } - Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(appInfo.loadIcon(mPm)); - return getBadgedIcon(icon, userId); + return mDrawableFactory.getBadgedIcon(appInfo, userId); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 5c25bfd6441c..78c71a11f3f5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -182,7 +182,8 @@ public class RecentsTaskLoadPlan { // Load the title, icon, and color ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey); String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription); - String titleDescription = loader.getAndUpdateContentDescription(taskKey, res); + String titleDescription = loader.getAndUpdateContentDescription(taskKey, + t.taskDescription, res); String dismissDescription = String.format(dismissDescFormat, titleDescription); String appInfoDescription = String.format(appInfoDescFormat, titleDescription); Drawable icon = isStackTask diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index e8ffb9150da7..5e78b61e021c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -449,7 +449,8 @@ public class RecentsTaskLoader { * Returns the cached task content description if the task key is not expired, updating the * cache if it is. */ - String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) { + String getAndUpdateContentDescription(Task.TaskKey taskKey, ActivityManager.TaskDescription td, + Resources res) { SystemServicesProxy ssp = Recents.getSystemServices(); // Return the cached content description if it exists @@ -461,8 +462,15 @@ public class RecentsTaskLoader { // All short paths failed, load the label from the activity info and cache it ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); if (activityInfo != null) { - label = ssp.getBadgedContentDescription(activityInfo, taskKey.userId, res); - mContentDescriptionCache.put(taskKey, label); + label = ssp.getBadgedContentDescription(activityInfo, taskKey.userId, td, res); + if (td == null) { + // Only add to the cache if the task description is null, otherwise, it is possible + // for the task description to change between calls without the last active time + // changing (ie. between preloading and Overview starting) which would lead to stale + // content descriptions + // TODO: Investigate improving this + mContentDescriptionCache.put(taskKey, label); + } return label; } // If the content description does not exist, return an empty label for now, but do not diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index d6f525655d56..1b5b2c65e5b2 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -48,6 +48,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.provider.Settings; +import android.service.autofill.FillEventHistory; import android.util.LocalLog; import android.util.Log; import android.util.Slog; @@ -184,7 +185,7 @@ public final class AutofillManagerService extends SystemService { } @Override - public void onStopUser(int userId) { + public void onCleanupUser(int userId) { synchronized (mLock) { removeCachedServiceLocked(userId); } @@ -211,7 +212,7 @@ public final class AutofillManagerService extends SystemService { /** * Peeks the service instance for a user. * - * @return service instance or null if not already present + * @return service instance or {@code null} if not already present */ @Nullable AutofillManagerServiceImpl peekServiceForUserLocked(int userId) { @@ -398,6 +399,21 @@ public final class AutofillManagerService extends SystemService { } @Override + public FillEventHistory getFillEventHistory() throws RemoteException { + UserHandle user = getCallingUserHandle(); + int uid = getCallingUid(); + + synchronized (mLock) { + AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier()); + if (service != null) { + return service.getFillEventHistory(uid); + } + } + + return null; + } + + @Override public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback) throws RemoteException { activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 57ef6d01a96b..e274e18e1b31 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -48,7 +48,9 @@ import android.os.UserManager; import android.provider.Settings; import android.service.autofill.AutofillService; import android.service.autofill.AutofillServiceInfo; +import android.service.autofill.FillEventHistory; import android.service.autofill.FillRequest; +import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; import android.text.TextUtils; import android.util.LocalLog; @@ -122,6 +124,10 @@ final class AutofillManagerServiceImpl { @GuardedBy("mLock") private final SparseArray<Session> mSessions = new SparseArray<>(); + /** The last selection */ + @GuardedBy("mLock") + private FillEventHistory mEventHistory; + /** * Receiver of assist data from the app's {@link Activity}. */ @@ -500,6 +506,72 @@ final class AutofillManagerServiceImpl { return mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()); } + /** + * Initializes the last fill selection after an autofill service returned a new + * {@link FillResponse}. + */ + void setLastResponse(int serviceUid, @NonNull FillResponse response) { + synchronized (mLock) { + mEventHistory = new FillEventHistory(serviceUid, response.getClientState()); + } + } + + /** + * Updates the last fill selection when an authentication was selected. + */ + void setAuthenticationSelected() { + synchronized (mLock) { + mEventHistory.addEvent( + new FillEventHistory.Event(FillEventHistory.Event.TYPE_AUTHENTICATION_SELECTED, null)); + } + } + + /** + * Updates the last fill selection when an dataset authentication was selected. + */ + void setDatasetAuthenticationSelected(@Nullable String selectedDataset) { + synchronized (mLock) { + mEventHistory.addEvent(new FillEventHistory.Event( + FillEventHistory.Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset)); + } + } + + /** + * Updates the last fill selection when an save Ui is shown. + */ + void setSaveShown() { + synchronized (mLock) { + mEventHistory.addEvent(new FillEventHistory.Event(FillEventHistory.Event.TYPE_SAVE_SHOWN, null)); + } + } + + /** + * Updates the last fill response when a dataset was selected. + */ + void setDatasetSelected(@Nullable String selectedDataset) { + synchronized (mLock) { + mEventHistory.addEvent( + new FillEventHistory.Event(FillEventHistory.Event.TYPE_DATASET_SELECTED, selectedDataset)); + } + } + + /** + * Gets the fill event history. + * + * @param callingUid The calling uid + * + * @return The history or {@code null} if there is none. + */ + FillEventHistory getFillEventHistory(int callingUid) { + synchronized (mLock) { + if (mEventHistory != null && mEventHistory.getServiceUid() == callingUid) { + return mEventHistory; + } + } + + return null; + } + void dumpLocked(String prefix, PrintWriter pw) { final String prefix2 = prefix + " "; @@ -528,6 +600,20 @@ final class AutofillManagerServiceImpl { mSessions.valueAt(i).dumpLocked(prefix2, pw); } } + + if (mEventHistory == null || mEventHistory.getEvents().size() == 0) { + pw.print(prefix); pw.println("No event on last fill response"); + } else { + pw.print(prefix); pw.println("Events of last fill response:"); + pw.print(prefix); + + int numEvents = mEventHistory.getEvents().size(); + for (int i = 0; i < numEvents; i++) { + FillEventHistory.Event event = mEventHistory.getEvents().get(i); + pw.println(" " + i + ": eventType=" + event.getType() + " datasetId=" + + event.getDatasetId()); + } + } } void destroySessionsLocked() { diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index 3badcfcb61cd..4d0f38042276 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -87,7 +87,7 @@ final class RemoteFillService implements DeathRecipient { private PendingRequest mPendingRequest; public interface FillServiceCallbacks { - void onFillRequestSuccess(@Nullable FillResponse response, + void onFillRequestSuccess(@Nullable FillResponse response, int serviceUid, @NonNull String servicePackageName, int requestId); void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); @@ -252,11 +252,11 @@ final class RemoteFillService implements DeathRecipient { } private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest, - FillResponse response, int requestId) { + int callingUid, FillResponse response, int requestId) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName(), - requestId); + mCallbacks.onFillRequestSuccess(response, callingUid, + mComponentName.getPackageName(), requestId); } }); } @@ -424,7 +424,7 @@ final class RemoteFillService implements DeathRecipient { RemoteFillService remoteService = mWeakService.get(); if (remoteService != null) { remoteService.dispatchOnFillRequestSuccess( - PendingFillRequest.this, response, requestId); + PendingFillRequest.this, getCallingUid(), response, requestId); } } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 7c3f3245461c..2b9961428a29 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -229,7 +229,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // FillServiceCallbacks @Override - public void onFillRequestSuccess(@Nullable FillResponse response, + public void onFillRequestSuccess(@Nullable FillResponse response, int serviceUid, @NonNull String servicePackageName, int requestId) { if (response == null) { if ((mFlags & FLAG_MANUAL_REQUEST) != 0) { @@ -241,6 +241,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } + mService.setLastResponse(serviceUid, response); + if ((response.getDatasets() == null || response.getDatasets().isEmpty()) && response.getAuthentication() == null) { // Response is "empty" from an UI point of view, need to notify client. @@ -314,6 +316,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState synchronized (mLock) { fillInIntent = createAuthFillInIntent(mStructure, extras); } + + mService.setAuthenticationSelected(); + mHandlerCaller.getHandler().post(() -> startAuthentication(intent, fillInIntent)); } @@ -442,7 +447,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ public boolean showSaveLocked() { if (mStructure == null) { - Slog.wtf(TAG, "showSaveLocked(): no mStructure"); + Slog.d(TAG, "showSaveLocked(): no mStructure"); return true; } if (mResponses == null) { @@ -542,6 +547,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } if (atLeastOneChanged) { + mService.setSaveShown(); getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName); return false; } @@ -764,7 +770,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState boolean saveOnAllViewsInvisible = false; SaveInfo saveInfo = mResponses.valueAt(getLastResponseIndex()).getSaveInfo(); if (saveInfo != null) { - saveOnAllViewsInvisible = saveInfo.saveOnAllViewsInvisible(); + saveOnAllViewsInvisible = + (saveInfo.getFlags() & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0; // We only need to track views if we want to save once they become invisible. if (saveOnAllViewsInvisible) { @@ -881,12 +888,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState synchronized (mLock) { // Autofill it directly... if (dataset.getAuthentication() == null) { + mService.setDatasetSelected(dataset.getId()); + autoFillApp(dataset); return; } // ...or handle authentication. // TODO(b/33197203 , b/35707731): make sure it's ignored if there is one already + mService.setDatasetAuthenticationSelected(dataset.getId()); mDatasetWaitingAuth = dataset; setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH); final Intent fillInIntent = createAuthFillInIntent(mStructure, null); diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 2e61550614f2..6502c012ef5b 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -25,7 +25,7 @@ option java_package com.android.server # This is logged when the screen on broadcast has completed 2727 power_screen_broadcast_stop (which|1|5),(wakelockCount|1|1) # This is logged when the screen is turned on or off. -2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1) +2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1),(latency|1|3) # This is logged when the partial wake lock (keeping the device awake # regardless of whether the screen is off) is acquired or released. 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d43fa0123925..8f1afa87b6a6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -10685,6 +10685,13 @@ public class ActivityManagerService extends IActivityManager.Stub return; } + // When a task is locked, dismiss the pinned stack if it exists + final PinnedActivityStack pinnedStack = mStackSupervisor.getStack( + PINNED_STACK_ID); + if (pinnedStack != null) { + mStackSupervisor.removeStackLocked(PINNED_STACK_ID); + } + // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode // is initiated by system after the pinning request was shown and locked mode is initiated // by an authorized app directly diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 17c7dde11726..7cdddc0ffeaf 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1178,6 +1178,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo * the activity is not currently visible and {@param noThrow} is not set. */ boolean checkEnterPictureInPictureState(String caller, boolean noThrow, boolean beforeStopping) { + if (!supportsPictureInPicture()) { + return false; + } + // Check app-ops and see if PiP is supported for this package if (!checkEnterPictureInPictureAppOpsState()) { return false; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 825e8ac0a698..85c5c647ceed 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -65,6 +65,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.ASSISTANT_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; +import static com.android.server.am.ActivityStack.ActivityState.STOPPED; +import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; @@ -1179,7 +1181,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { final ActivityRecord r = activities.get(activityNdx); - if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED + if (r.state == STOPPING || r.state == STOPPED || r.state == ActivityState.PAUSED || r.state == ActivityState.PAUSING) { r.setSleeping(true); } @@ -1362,7 +1364,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev); if (prev != null) { - final boolean wasStopping = prev.state == ActivityState.STOPPING; + final boolean wasStopping = prev.state == STOPPING; prev.state = ActivityState.PAUSED; if (prev.finishing) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev); @@ -1383,7 +1385,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // We are also stopping, the stop request must have gone soon after the pause. // We can't clobber it, because the stop confirmation will not be handled. // We don't need to schedule another stop, we only need to let it happen. - prev.state = ActivityState.STOPPING; + prev.state = STOPPING; } else if ((!prev.visible && !hasVisibleBehindActivity()) || mService.isSleepingOrShuttingDownLocked()) { // If we were visible then resumeTopActivities will release resources before @@ -2002,10 +2004,17 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // keeping the screen frozen. if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state); try { + final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState( + "makeInvisible", true /* noThrow */, true /* beforeStopping */); + // We don't want to call setVisible(false) to avoid notifying the client of this + // intermittent invisible state if it can enter Pip and isn't stopped or stopping. + if (!canEnterPictureInPicture || r.state == STOPPING || r.state == STOPPED) { + r.setVisible(false); + } + switch (r.state) { case STOPPING: case STOPPED: - r.setVisible(false); if (r.app != null && r.app.thread != null) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Scheduling invisibility: " + r); @@ -2024,25 +2033,16 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // This case created for transitioning activities from // translucent to opaque {@link Activity#convertToOpaque}. if (visibleBehind == r) { - r.setVisible(false); releaseBackgroundResources(r); } else { // If this activity is in a state where it can currently enter // picture-in-picture, then don't immediately schedule the idle now in case // the activity tries to enterPictureInPictureMode() later. Otherwise, // we will try and stop the activity next time idle is processed. - final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState( - "makeInvisible", true /* noThrow */, true /* beforeStopping */); if (canEnterPictureInPicture) { - // We set r.visible=false so that Stop will later - // call setVisible for us. In this case - // we don't want to call setVisible(false) to avoid - // notifying the client of this intermittent invisible - // state. + // We set r.visible=false so that Stop will later call setVisible for us r.visible = false; - } else { - r.setVisible(false); } addToStopping(r, true /* scheduleIdle */, canEnterPictureInPicture /* idleDelayed */); @@ -2318,9 +2318,20 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); + final boolean prevCanPip = prev != null && prev.checkEnterPictureInPictureState( + "resumeTopActivity", true /* noThrow */, userLeaving /* beforeStopping */); // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity - // to be paused, while at the same time resuming the new resume activity + // to be paused, while at the same time resuming the new resume activity only if the + // previous activity can't go into Pip since we want to give Pip activities a chance to + // enter Pip before resuming the next activity. final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0; + // TODO: This would be go to have however, the various call points that pass in + // prev need to be corrected first. In some cases the prev is equal to the next e.g. launch + // an app from home. And, is come other cases it is null e.g. press home button after + // launching an app. The doc on the method says prev. is null expect for the case we are + // coming from pause. We need to see if that is a valid thing and also if all the code in + // this method using prev. are setup to function like that. + //&& !prevCanPip; boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false); if (mResumedActivity != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, @@ -3360,11 +3371,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai r.stopped = false; if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPING: " + r + " (stop requested)"); - r.state = ActivityState.STOPPING; + r.state = STOPPING; if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Stopping visible=" + r.visible + " for " + r); if (!r.visible) { - r.setVisibility(false); + r.setVisible(false); } EventLogTags.writeAmStopActivity( r.userId, System.identityHashCode(r), r.shortComponentName); @@ -3382,7 +3393,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Just in case, assume it to be stopped. r.stopped = true; if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r); - r.state = ActivityState.STOPPED; + r.state = STOPPED; if (r.deferRelaunchUntilPaused) { destroyActivityLocked(r, true, "stop-except"); } @@ -3687,7 +3698,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPING: "+ r + " (finish requested)"); - r.state = ActivityState.STOPPING; + r.state = STOPPING; if (oomAdj) { mService.updateOomAdjLocked(); } @@ -3712,8 +3723,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai || (prevState == ActivityState.PAUSED && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID)) || finishingActivityInNonFocusedStack - || prevState == ActivityState.STOPPING - || prevState == ActivityState.STOPPED + || prevState == STOPPING + || prevState == STOPPED || prevState == ActivityState.INITIALIZING) { r.makeFinishingLocked(); boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm"); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 43ae4b22ba63..152d5f463988 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2878,6 +2878,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mWindowManager.deferSurfaceLayout(); + // This will clear the pinned stack by moving an existing task to the full screen stack, + // ensuring only one task is present. + moveTasksToFullscreenStackLocked(PINNED_STACK_ID, !ON_TOP); + // Need to make sure the pinned stack exist so we can resize it below... final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP); diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index f8a4d4b21414..d42b6a7647ce 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -48,6 +48,7 @@ import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.util.XmlUtils; @@ -445,10 +446,23 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta final Rect bounds = updateOverrideConfigurationFromLaunchBounds(); final Configuration overrideConfig = getOverrideConfiguration(); - mWindowContainerController = new TaskWindowContainerController(taskId, this, + setWindowContainerController(new TaskWindowContainerController(taskId, this, getStack().getWindowContainerController(), userId, bounds, overrideConfig, mResizeMode, mSupportsPictureInPicture, isHomeTask(), onTop, showForAllUsers, - lastTaskDescription); + lastTaskDescription)); + } + + /** + * Should only be invoked from {@link #createWindowContainer(boolean, boolean)}. + */ + @VisibleForTesting + protected void setWindowContainerController(TaskWindowContainerController controller) { + if (mWindowContainerController != null) { + throw new IllegalArgumentException("Window container=" + mWindowContainerController + + " already created for task=" + this); + } + + mWindowContainerController = controller; } void removeWindowContainer() { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e7617f5f5c7b..aa1b74ce4577 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -520,7 +520,11 @@ public class AudioService extends IAudioService.Stub private int mPrevVolDirection = AudioManager.ADJUST_SAME; // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume // is controlled by Vol keys. - private int mVolumeControlStream = -1; + private int mVolumeControlStream = -1; + // interpretation of whether the volume stream has been selected by the user by clicking on a + // volume slider to change which volume is controlled by the volume keys. Is false + // when mVolumeControlStream is -1. + private boolean mUserSelectedVolumeControlStream = false; private final Object mForceControlStreamLock = new Object(); // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system // server process so in theory it is not necessary to monitor the client death. @@ -1224,14 +1228,29 @@ public class AudioService extends IAudioService.Stub private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller, int uid) { if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType - + ", flags=" + flags + ", caller=" + caller); - int streamType; - boolean isMute = isMuteAdjust(direction); - if (mVolumeControlStream != -1) { + + ", flags=" + flags + ", caller=" + caller + + ", volControlStream=" + mVolumeControlStream + + ", userSelect=" + mUserSelectedVolumeControlStream); + final int streamType; + if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1 streamType = mVolumeControlStream; } else { - streamType = getActiveStreamType(suggestedStreamType); + final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType); + final boolean activeForReal; + if (maybeActiveStreamType == AudioSystem.STREAM_MUSIC) { + activeForReal = isAfMusicActiveRecently(0); + } else { + activeForReal = AudioSystem.isStreamActive(maybeActiveStreamType, 0); + } + if (activeForReal || mVolumeControlStream == -1) { + streamType = maybeActiveStreamType; + } else { + streamType = mVolumeControlStream; + } } + + final boolean isMute = isMuteAdjust(direction); + ensureValidStreamType(streamType); final int resolvedStream = mStreamVolumeAlias[streamType]; @@ -1707,13 +1726,18 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#forceVolumeControlStream(int) */ public void forceVolumeControlStream(int streamType, IBinder cb) { + if (DEBUG_VOL) { Log.d(TAG, String.format("forceVolumeControlStream(%d)", streamType)); } synchronized(mForceControlStreamLock) { + if (mVolumeControlStream != -1 && streamType != -1) { + mUserSelectedVolumeControlStream = true; + } mVolumeControlStream = streamType; if (mVolumeControlStream == -1) { if (mForceControlStreamClient != null) { mForceControlStreamClient.release(); mForceControlStreamClient = null; } + mUserSelectedVolumeControlStream = false; } else { mForceControlStreamClient = new ForceControlStreamClient(cb); } @@ -1744,6 +1768,7 @@ public class AudioService extends IAudioService.Stub } else { mForceControlStreamClient = null; mVolumeControlStream = -1; + mUserSelectedVolumeControlStream = false; } } } diff --git a/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java b/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java index ce976d29216b..acedafc4025c 100644 --- a/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java +++ b/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java @@ -15,19 +15,25 @@ */ package com.android.server.notification; +import android.util.Slog; + import java.util.Comparator; /** * Sorts notifications by their global sort key. */ public class GlobalSortKeyComparator implements Comparator<NotificationRecord> { + private final static String TAG = "GlobalSortComp"; + @Override public int compare(NotificationRecord left, NotificationRecord right) { if (left.getGlobalSortKey() == null) { - throw new IllegalStateException("Missing left global sort key: " + left); + Slog.wtf(TAG, "Missing left global sort key: " + left); + return 1; } if (right.getGlobalSortKey() == null) { - throw new IllegalStateException("Missing right global sort key: " + right); + Slog.wtf(TAG, "Missing right global sort key: " + right); + return -1; } return left.getGlobalSortKey().compareTo(right.getGlobalSortKey()); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index cc3948ed1a59..8a6a940e6669 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1874,10 +1874,9 @@ public class NotificationManagerService extends SystemService { int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), incomingUserId, true, false, "getAppActiveNotifications", pkg); - final ArrayMap<String, StatusBarNotification> map - = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); - synchronized (mNotificationLock) { + final ArrayMap<String, StatusBarNotification> map + = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); final int N = mNotificationList.size(); for (int i = 0; i < N; i++) { StatusBarNotification sbn = sanitizeSbn(pkg, userId, @@ -1900,11 +1899,10 @@ public class NotificationManagerService extends SystemService { map.put(sbn.getKey(), sbn); // pending update overwrites existing post here } } + final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); + list.addAll(map.values()); + return new ParceledListSlice<StatusBarNotification>(list); } - - final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); - list.addAll(map.values()); - return new ParceledListSlice<StatusBarNotification>(list); } private StatusBarNotification sanitizeSbn(String pkg, int userId, @@ -2036,8 +2034,10 @@ public class NotificationManagerService extends SystemService { long identity = Binder.clearCallingIdentity(); try { // allow bound services to disable themselves - final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - info.getOwner().setComponentState(info.component, false); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + info.getOwner().setComponentState(info.component, false); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2101,8 +2101,10 @@ public class NotificationManagerService extends SystemService { String key, String snoozeCriterionId) { long identity = Binder.clearCallingIdentity(); try { - final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2118,8 +2120,10 @@ public class NotificationManagerService extends SystemService { long duration) { long identity = Binder.clearCallingIdentity(); try { - final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - snoozeNotificationInt(key, duration, null, info); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + snoozeNotificationInt(key, duration, null, info); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2134,9 +2138,11 @@ public class NotificationManagerService extends SystemService { public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) { long identity = Binder.clearCallingIdentity(); try { - final ManagedServiceInfo info = - mNotificationAssistants.checkServiceTokenLocked(token); - unsnoozeNotificationInt(key, info); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = + mNotificationAssistants.checkServiceTokenLocked(token); + unsnoozeNotificationInt(key, info); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2734,7 +2740,10 @@ public class NotificationManagerService extends SystemService { } private void verifyPrivilegedListener(INotificationListener token, UserHandle user) { - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + ManagedServiceInfo info; + synchronized (mNotificationLock) { + info = mListeners.checkServiceTokenLocked(token); + } if (!hasCompanionDevice(info)) { throw new SecurityException(info + " does not have access"); } @@ -3099,8 +3108,10 @@ public class NotificationManagerService extends SystemService { @Override public void run() { synchronized (mNotificationLock) { - removeForegroundServiceFlagByListLocked(mEnqueuedNotifications, pkg, notificationId, userId); - removeForegroundServiceFlagByListLocked(mNotificationList, pkg, notificationId, userId); + removeForegroundServiceFlagByListLocked( + mEnqueuedNotifications, pkg, notificationId, userId); + removeForegroundServiceFlagByListLocked( + mNotificationList, pkg, notificationId, userId); } } }); @@ -3229,8 +3240,12 @@ public class NotificationManagerService extends SystemService { private void doDebugOnlyToast(CharSequence toastText) { if (Build.IS_DEBUGGABLE) { - Toast toast = Toast.makeText(getContext(), toastText, Toast.LENGTH_LONG); - toast.show(); + try { + Toast toast = Toast.makeText(getContext(), toastText, Toast.LENGTH_LONG); + toast.show(); + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to toast with text: " + toastText, e); + } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 312c310428a5..5535d1790e5d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4218,8 +4218,10 @@ public class PackageManagerService extends IPackageManager.Stub } SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getName(), - libInfo.getVersion(), libInfo.getType(), libInfo.getDeclaringPackage(), - getPackagesUsingSharedLibraryLPr(libInfo, flags, userId)); + // TODO: Remove cast for lib version once internally we support longs. + (int) libInfo.getVersion(), libInfo.getType(), + libInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(libInfo, + flags, userId)); if (result == null) { result = new ArrayList<>(); @@ -17593,7 +17595,8 @@ public class PackageManagerService extends IPackageManager.Stub for (int i = 0; i < versionCount; i++) { SharedLibraryEntry libEntry = versionedLib.valueAt(i); if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey( - libEntry.info.getVersion()) < 0) { + // TODO: Remove cast for lib version once internally we support longs. + (int) libEntry.info.getVersion()) < 0) { continue; } // TODO: We will change version code to long, so in the new API it is long diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 8f114361ccff..f5bb082fac6d 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -406,11 +406,7 @@ final class Notifier { mHandler.post(new Runnable() { @Override public void run() { - LogMaker log = new LogMaker(MetricsEvent.SCREEN); - log.setType(MetricsEvent.TYPE_OPEN); - log.setSubtype(0); // not user initiated - MetricsLogger.action(log); - EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); + // Note a SCREEN tron event is logged in PowerManagerService. mPolicy.startedWakingUp(); } }); @@ -470,7 +466,7 @@ final class Notifier { log.setType(MetricsEvent.TYPE_CLOSE); log.setSubtype(why); MetricsLogger.action(log); - EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0); + EventLogTags.writePowerScreenState(0, why, 0, 0, 0); mPolicy.finishedGoingToSleep(why); } }); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index cf597b052c10..4f239a5cba23 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -32,6 +32,7 @@ import android.hardware.SystemSensorManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.hardware.power.V1_0.PowerHint; +import android.metrics.LogMaker; import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryManagerInternal; @@ -75,6 +76,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; @@ -188,6 +191,11 @@ public final class PowerManagerService extends SystemService // System property indicating that the screen should remain off until an explicit user action private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent"; + private static final String TRACE_SCREEN_ON = "Screen turning on"; + + /** If turning screen on takes more than this long, we show a warning on logcat. */ + private static final int SCREEN_ON_LATENCY_WARNING_MS = 200; + /** Constants for {@link #shutdownOrRebootInternal} */ @Retention(RetentionPolicy.SOURCE) @IntDef({HALT_MODE_SHUTDOWN, HALT_MODE_REBOOT, HALT_MODE_REBOOT_SAFE_MODE}) @@ -1369,6 +1377,8 @@ public final class PowerManagerService extends SystemService return false; } + Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0); + Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp"); try { switch (mWakefulness) { @@ -1551,6 +1561,23 @@ public final class PowerManagerService extends SystemService } } + private void logScreenOn() { + Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0); + + final int latencyMs = (int) (SystemClock.uptimeMillis() - mLastWakeTime); + + LogMaker log = new LogMaker(MetricsEvent.SCREEN); + log.setType(MetricsEvent.TYPE_OPEN); + log.setSubtype(0); // not user initiated + log.setLatency(latencyMs); // How long it took. + MetricsLogger.action(log); + EventLogTags.writePowerScreenState(1, 0, 0, 0, latencyMs); + + if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) { + Slog.w(TAG, "Screen on took " + latencyMs+ " ms"); + } + } + private void finishWakefulnessChangeIfNeededLocked() { if (mWakefulnessChanging && mDisplayReady) { if (mWakefulness == WAKEFULNESS_DOZING @@ -1560,6 +1587,9 @@ public final class PowerManagerService extends SystemService if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) { logSleepTimeoutRecapturedLocked(); } + if (mWakefulness == WAKEFULNESS_AWAKE) { + logScreenOn(); + } mWakefulnessChanging = false; mNotifier.onWakefulnessChangeFinished(); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index bfa1b9988b2f..e82ba9cee919 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -742,8 +742,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean forceEphemeralUsers = false; // Can only be set by a device owner. boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner. - // one notification after enabling + 3 more after reboots - static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 4; + // one notification after enabling + one more after reboots + static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2; int numNetworkLoggingNotifications = 0; long lastNetworkLoggingNotificationTimeMs = 0; // Time in milliseconds since epoch diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java new file mode 100644 index 000000000000..24cb72e8b0fb --- /dev/null +++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.notification; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.os.UserHandle; +import android.service.notification.StatusBarNotification; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class GlobalSortKeyComparatorTest { + + private final String PKG = "PKG"; + private final int UID = 1111111; + private static final String TEST_CHANNEL_ID = "test_channel_id"; + + @Test + public void testComparator() throws Exception { + Notification n = new Notification.Builder( + InstrumentationRegistry.getContext(), TEST_CHANNEL_ID) + .build(); + NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + left.setGlobalSortKey("first"); + + NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + right.setGlobalSortKey("second"); + + NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + + + final List<NotificationRecord> expected = new ArrayList<>(); + expected.add(left); + expected.add(right); + expected.add(last); + + List<NotificationRecord> actual = new ArrayList<>(); + actual.addAll(expected); + Collections.shuffle(actual); + + Collections.sort(actual, new GlobalSortKeyComparator()); + + assertEquals(expected, actual); + } + + @Test + public void testNoCrash_leftNull() throws Exception { + Notification n = new Notification.Builder( + InstrumentationRegistry.getContext(), TEST_CHANNEL_ID) + .build(); + NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + + NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + right.setGlobalSortKey("not null"); + + final List<NotificationRecord> expected = new ArrayList<>(); + expected.add(right); + expected.add(left); + + List<NotificationRecord> actual = new ArrayList<>(); + actual.addAll(expected); + Collections.shuffle(actual); + + Collections.sort(actual, new GlobalSortKeyComparator()); + + assertEquals(expected, actual); + } + + @Test + public void testNoCrash_rightNull() throws Exception { + Notification n = new Notification.Builder( + InstrumentationRegistry.getContext(), TEST_CHANNEL_ID) + .build(); + NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + left.setGlobalSortKey("not null"); + + NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + + final List<NotificationRecord> expected = new ArrayList<>(); + expected.add(left); + expected.add(right); + + List<NotificationRecord> actual = new ArrayList<>(); + actual.addAll(expected); + Collections.shuffle(actual); + + Collections.sort(actual, new GlobalSortKeyComparator()); + + assertEquals(expected, actual); + } + + private NotificationChannel getDefaultChannel() { + return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name", + NotificationManager.IMPORTANCE_LOW); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java index 54ecab3af542..f75d49cae574 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -16,7 +16,8 @@ package com.android.server.am; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import android.content.ComponentName; import android.platform.test.annotations.Presubmit; @@ -36,50 +37,61 @@ import org.junit.Test; @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityRecordTests extends ActivityTestsBase { + private static final int TEST_STACK_ID = 100; + private final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); @Test public void testStackCleanupOnClearingTask() throws Exception { final ActivityManagerService service = createActivityManagerService(); - final TestActivityStack testStack = new ActivityStackBuilder(service).build(); - final TaskRecord task = createTask(service, testActivityComponent, testStack); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); record.setTask(null); - assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); + assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); } @Test public void testStackCleanupOnActivityRemoval() throws Exception { final ActivityManagerService service = createActivityManagerService(); - final TestActivityStack testStack = new ActivityStackBuilder(service).build(); - final TaskRecord task = createTask(service, testActivityComponent, testStack); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); task.removeActivity(record); - assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); + assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); } @Test public void testStackCleanupOnTaskRemoval() throws Exception { final ActivityManagerService service = createActivityManagerService(); - final TestActivityStack testStack = new ActivityStackBuilder(service).build(); - final TaskRecord task = createTask(service, testActivityComponent, testStack); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, task); - testStack.removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); - assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1); + service.mStackSupervisor.getStack(TEST_STACK_ID) + .removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); + + // Stack should be gone on task removal. + assertNull(service.mStackSupervisor.getStack(TEST_STACK_ID)); } @Test public void testNoCleanupMovingActivityInSameStack() throws Exception { final ActivityManagerService service = createActivityManagerService(); - final TestActivityStack testStack = new ActivityStackBuilder(service).build(); - final TaskRecord oldTask = createTask(service, testActivityComponent, testStack); + final TaskRecord oldTask = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord record = createActivity(service, testActivityComponent, oldTask); - final TaskRecord newTask = createTask(service, testActivityComponent, testStack); + final TaskRecord newTask = createTask(service, testActivityComponent, TEST_STACK_ID); record.reparent(newTask, 0, null /*reason*/); - assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 0); + assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 0); + } + + private static int getActivityRemovedFromStackCount(ActivityManagerService service, + int stackId) { + final ActivityStack stack = service.mStackSupervisor.getStack(stackId); + if (stack instanceof ActivityStackReporter) { + return ((ActivityStackReporter) stack).onActivityRemovedFromStackInvocationCount(); + } + + return -1; } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index 8423affecd30..fc9ab9635c57 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -16,8 +16,14 @@ package com.android.server.am; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import android.content.ComponentName; +import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; @@ -25,6 +31,10 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.runner.RunWith; import org.junit.Test; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; /** @@ -37,6 +47,9 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityStackSupervisorTests extends ActivityTestsBase { + private final ComponentName testActivityComponent = + ComponentName.unflattenFromString("com.foo/.BarActivity"); + /** * This test ensures that we do not try to restore a task based off an invalid task id. The * stack supervisor is a test version so there will be no tasks present. We should expect @@ -49,4 +62,59 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, 0 /*stackId*/); assertNull(task); } + + /** + * This test ensures that an existing task in the pinned stack is moved to the fullscreen + * activity stack when a new task is added. + */ + @Test + public void testReplacingTaskInPinnedStack() throws Exception { + final ActivityManagerService service = createActivityManagerService(); + final TaskRecord firstTask = createTask(service, testActivityComponent, + FULLSCREEN_WORKSPACE_STACK_ID); + final ActivityRecord firstActivity = createActivity(service, testActivityComponent, + firstTask); + // Create a new task on the full screen stack + final TaskRecord secondTask = createTask(service, testActivityComponent, + FULLSCREEN_WORKSPACE_STACK_ID); + final ActivityRecord secondActivity = createActivity(service, testActivityComponent, + secondTask); + service.mStackSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack", + service.mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID)); + + // Ensure full screen stack has both tasks. + ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask, + secondTask); + + // Move first activity to pinned stack. + service.mStackSupervisor.moveActivityToPinnedStackLocked(firstActivity, + new Rect() /*sourceBounds*/, 0f /*aspectRatio*/, false, "initialMove"); + + // Ensure a task has moved over. + ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, firstTask); + ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, secondTask); + + // Move second activity to pinned stack. + service.mStackSupervisor.moveActivityToPinnedStackLocked(secondActivity, + new Rect() /*sourceBounds*/, 0f /*aspectRatio*/ /*destBounds*/, false, "secondMove"); + + // Ensure stacks have swapped tasks. + ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, secondTask); + ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask); + } + + private static void ensureStackPlacement(ActivityStackSupervisor supervisor, int stackId, + TaskRecord... tasks) { + final ActivityStack stack = supervisor.getStack(stackId); + final ArrayList<TaskRecord> stackTasks = stack.getAllTasks(); + assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); + + if (tasks == null) { + return; + } + + for (TaskRecord task : tasks) { + assertTrue(stackTasks.contains(task)); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 1d80b336becc..f42abf1927f0 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -37,28 +37,27 @@ import org.junit.Test; @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityStackTests extends ActivityTestsBase { - private final ComponentName testActivityComponent = + private static final int TEST_STACK_ID = 100; + private static final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); @Test public void testEmptyTaskCleanupOnRemove() throws Exception { final ActivityManagerService service = createActivityManagerService(); - final TestActivityStack testStack = new ActivityStackBuilder(service).build(); - final TaskRecord task = createTask(service, testActivityComponent, testStack); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); assertNotNull(task.getWindowContainerController()); - testStack.removeTask(task, "testEmptyTaskCleanupOnRemove", - ActivityStack.REMOVE_TASK_MODE_DESTROYING); + service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, + "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNull(task.getWindowContainerController()); } @Test public void testOccupiedTaskCleanupOnRemove() throws Exception { final ActivityManagerService service = createActivityManagerService(); - final TestActivityStack testStack = new ActivityStackBuilder(service).build(); - final TaskRecord task = createTask(service, testActivityComponent, testStack); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); assertNotNull(task.getWindowContainerController()); - testStack.removeTask(task, "testOccupiedTaskCleanupOnRemove", - ActivityStack.REMOVE_TASK_MODE_DESTROYING); + service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, + "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); assertNotNull(task.getWindowContainerController()); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 3bf0e5ff86aa..082708442032 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -17,6 +17,11 @@ package com.android.server.am; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; + +import org.mockito.invocation.InvocationOnMock; import android.app.ActivityManager; import android.content.ComponentName; @@ -33,6 +38,7 @@ import com.android.server.AttributeCache; import com.android.server.wm.AppWindowContainerController; import com.android.server.wm.StackWindowController; +import com.android.server.wm.TaskWindowContainerController; import com.android.server.wm.WindowManagerService; import com.android.server.wm.WindowTestUtils; import org.junit.After; @@ -64,16 +70,15 @@ public class ActivityTestsBase { protected ActivityManagerService createActivityManagerService() { final ActivityManagerService service = new TestActivityManagerService(mContext); - service.mWindowManager = WindowTestUtils.getWindowManagerService(mContext); + service.mWindowManager = WindowTestUtils.getMockWindowManagerService(); return service; } - protected static TestActivityStack createActivityStack(ActivityManagerService service, + protected static ActivityStack createActivityStack(ActivityManagerService service, int stackId, int displayId, boolean onTop) { if (service.mStackSupervisor instanceof TestActivityStackSupervisor) { - final TestActivityStack stack = ((TestActivityStackSupervisor) service.mStackSupervisor) + return ((TestActivityStackSupervisor) service.mStackSupervisor) .createTestStack(service, stackId, onTop); - return stack; } return null; @@ -103,7 +108,7 @@ public class ActivityTestsBase { } protected static TaskRecord createTask(ActivityManagerService service, - ComponentName component, ActivityStack stack) { + ComponentName component, int stackId) { final ActivityInfo aInfo = new ActivityInfo(); aInfo.applicationInfo = new ApplicationInfo(); aInfo.applicationInfo.packageName = component.getPackageName(); @@ -113,13 +118,16 @@ public class ActivityTestsBase { final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/, null /*_taskDescription*/, new ActivityManager.TaskThumbnailInfo()); + final ActivityStack stack = service.mStackSupervisor.getStack(stackId, + true /*createStaticStackIfNeeded*/, true /*onTop*/); stack.addTask(task, true, "creating test task"); task.setStack(stack); - task.createWindowContainer(true, true); + task.setWindowContainerController(mock(TaskWindowContainerController.class)); return task; } + /** * An {@link ActivityManagerService} subclass which provides a test * {@link ActivityStackSupervisor}. @@ -127,6 +135,9 @@ public class ActivityTestsBase { protected static class TestActivityManagerService extends ActivityManagerService { public TestActivityManagerService(Context context) { super(context); + mSupportsMultiWindow = true; + mSupportsMultiDisplay = true; + mWindowManager = WindowTestUtils.getWindowManagerService(context); } @Override @@ -142,6 +153,12 @@ public class ActivityTestsBase { protected static class TestActivityStackSupervisor extends ActivityStackSupervisor { public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) { super(service, looper); + mWindowManager = prepareMockWindowManager(); + } + + // No home stack is set. + @Override + void moveHomeStackToFront(String reason) { } // Invoked during {@link ActivityStack} creation. @@ -149,18 +166,45 @@ public class ActivityTestsBase { void updateUIDsPresentOnDisplay() { } - public TestActivityStack createTestStack(ActivityManagerService service, int stackId, - boolean onTop) { + // Just return the current front task. + @Override + ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) { + return mFocusedStack; + } + + // Called when moving activity to pinned stack. + @Override + void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, + boolean preserveWindows) { + } + + public <T extends ActivityStack> T createTestStack(ActivityManagerService service, + int stackId, boolean onTop) { final ActivityDisplay display = new ActivityDisplay(); final TestActivityContainer container = new TestActivityContainer(service, stackId, display, onTop); - return container.getStack(); + mActivityContainers.put(stackId, container); + return (T) container.getStack(); + } + + @Override + protected <T extends ActivityStack> T getStack(int stackId, + boolean createStaticStackIfNeeded, boolean createOnTop) { + final T stack = super.getStack(stackId, createStaticStackIfNeeded, createOnTop); + + if (stack != null || !createStaticStackIfNeeded) { + return stack; + } + + return createTestStack(mService, stackId, createOnTop); } private class TestActivityContainer extends ActivityContainer { - private ActivityManagerService mService; - private TestActivityStack mStack; + private final ActivityManagerService mService; + private boolean mOnTop; + private int mStackId; + private ActivityStack mStack; TestActivityContainer(ActivityManagerService service, int stackId, ActivityDisplay activityDisplay, boolean onTop) { @@ -174,12 +218,16 @@ public class ActivityTestsBase { // we cannot set {@link mService} by the time the super constructor calling this // method is invoked. mOnTop = onTop; + mStackId = stackId; } - public TestActivityStack getStack() { + public ActivityStack getStack() { if (mStack == null) { - mStack = new TestActivityStack(this, - new RecentTasks(mService, mService.mStackSupervisor), mOnTop); + final RecentTasks recents = + new RecentTasks(mService, mService.mStackSupervisor); + mStack = mStackId == ActivityManager.StackId.PINNED_STACK_ID + ? new PinnedActivityStack(this, recents, mOnTop) + : new TestActivityStack(this, recents, mOnTop); } return mStack; @@ -187,13 +235,31 @@ public class ActivityTestsBase { } } + private static WindowManagerService prepareMockWindowManager() { + final WindowManagerService service = mock(WindowManagerService.class); + + doAnswer((InvocationOnMock invocationOnMock) -> { + final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); + if (runnable != null) { + runnable.run(); + } + return null; + }).when(service).inSurfaceTransaction(any()); + + return service; + } + + protected interface ActivityStackReporter { + int onActivityRemovedFromStackInvocationCount(); + } + /** * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a * method is called. Note that its functionality depends on the implementations of the * construction arguments. */ protected static class TestActivityStack<T extends StackWindowController> - extends ActivityStack<T> { + extends ActivityStack<T> implements ActivityStackReporter { private int mOnActivityRemovedFromStackCount = 0; private T mContainerController; TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer, @@ -208,6 +274,7 @@ public class ActivityTestsBase { } // Returns the number of times {@link #onActivityRemovedFromStack} has been called + @Override public int onActivityRemovedFromStackInvocationCount() { return mOnActivityRemovedFromStackCount; } @@ -225,6 +292,7 @@ public class ActivityTestsBase { } } + protected static class ActivityStackBuilder { private boolean mOnTop = true; private int mStackId = 0; @@ -251,7 +319,7 @@ public class ActivityTestsBase { return this; } - public TestActivityStack build() { + public ActivityStack build() { return createActivityStack(mService, mStackId, mDisplayId, mOnTop); } } diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java index 929a73d805c0..c314de4f13eb 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java @@ -27,6 +27,7 @@ import android.os.UserManagerInternal; import android.support.test.InstrumentationRegistry; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; +import android.util.IconDrawableFactory; import com.android.server.LocalServices; @@ -155,9 +156,9 @@ public class UserManagerServiceCreateProfileTest { public void testNumberOfBadges() { assertTrue("Max profiles greater than number of badges", UserManagerService.MAX_MANAGED_PROFILES - <= ApplicationPackageManager.CORP_BADGE_COLORS.length); + <= IconDrawableFactory.CORP_BADGE_COLORS.length); assertEquals("Num colors doesn't match number of badge labels", - ApplicationPackageManager.CORP_BADGE_COLORS.length, + IconDrawableFactory.CORP_BADGE_COLORS.length, ApplicationPackageManager.CORP_BADGE_LABEL_RES_ID.length); } diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index fbeda0a9191c..9392e8ee2b5c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -90,6 +90,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { return null; }).when(am).notifyKeyguardFlagsChanged(any()); } + sWm = WindowManagerService.main(context, mock(InputManagerService.class), true, false, false, new TestWindowManagerPolicy()); } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java index 3a443575332e..ae3eb522837f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java @@ -48,6 +48,13 @@ public class WindowTestUtils { } /** + * Retrieves an instance of a mock {@link WindowManagerService}. + */ + public static WindowManagerService getMockWindowManagerService() { + return mock(WindowManagerService.class); + } + + /** * Creates a mock instance of {@link StackWindowController}. */ public static StackWindowController createMockStackWindowContainerController() { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 3d51c4cd51ae..8ee6454ebd66 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -911,7 +911,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceSoftwareVersion() { - return getDeviceSoftwareVersion(getDefaultSim()); + return getDeviceSoftwareVersion(getSlotIndex()); } /** @@ -997,7 +997,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getImei() { - return getImei(getDefaultSim()); + return getImei(getSlotIndex()); } /** @@ -1029,7 +1029,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getMeid() { - return getMeid(getDefaultSim()); + return getMeid(getSlotIndex()); } /** @@ -1059,7 +1059,7 @@ public class TelephonyManager { */ /** {@hide}*/ public String getNai() { - return getNai(getDefaultSim()); + return getNai(getSlotIndex()); } /** @@ -1303,7 +1303,7 @@ public class TelephonyManager { } private int getPhoneTypeFromProperty() { - return getPhoneTypeFromProperty(getDefaultPhone()); + return getPhoneTypeFromProperty(getPhoneId()); } /** {@hide} */ @@ -1317,7 +1317,7 @@ public class TelephonyManager { } private int getPhoneTypeFromNetworkType() { - return getPhoneTypeFromNetworkType(getDefaultPhone()); + return getPhoneTypeFromNetworkType(getPhoneId()); } /** {@hide} */ @@ -1500,7 +1500,7 @@ public class TelephonyManager { * on a CDMA network). */ public String getNetworkOperator() { - return getNetworkOperatorForPhone(getDefaultPhone()); + return getNetworkOperatorForPhone(getPhoneId()); } /** @@ -1546,7 +1546,7 @@ public class TelephonyManager { * @see #createForPhoneAccountHandle(PhoneAccountHandle) */ public String getNetworkSpecifier() { - return String.valueOf(mSubId); + return String.valueOf(getSubId()); } /** @@ -1565,7 +1565,7 @@ public class TelephonyManager { public PersistableBundle getCarrierConfig() { CarrierConfigManager carrierConfigManager = mContext .getSystemService(CarrierConfigManager.class); - return carrierConfigManager.getConfigForSubId(mSubId); + return carrierConfigManager.getConfigForSubId(getSubId()); } /** @@ -1602,7 +1602,7 @@ public class TelephonyManager { * on a CDMA network). */ public String getNetworkCountryIso() { - return getNetworkCountryIsoForPhone(getDefaultPhone()); + return getNetworkCountryIsoForPhone(getPhoneId()); } /** @@ -1748,6 +1748,9 @@ public class TelephonyManager { * Returns a constant indicating the radio technology (network type) * currently in use on the device for data transmission. * + * If this object has been created with {@link #createForSubscriptionId}, applies to the given + * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * * <p> * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} @@ -1772,7 +1775,7 @@ public class TelephonyManager { * @see #NETWORK_TYPE_HSPAP */ public int getDataNetworkType() { - return getDataNetworkType(getSubId()); + return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId())); } /** @@ -1996,7 +1999,7 @@ public class TelephonyManager { * @return true if a ICC card is present */ public boolean hasIccCard() { - return hasIccCard(getDefaultSim()); + return hasIccCard(getSlotIndex()); } /** @@ -2037,7 +2040,7 @@ public class TelephonyManager { * @see #SIM_STATE_CARD_RESTRICTED */ public int getSimState() { - int slotIndex = getDefaultSim(); + int slotIndex = getSlotIndex(); // slotIndex may be invalid due to sim being absent. In that case query all slots to get // sim state if (slotIndex < 0) { @@ -2166,7 +2169,7 @@ public class TelephonyManager { * @see #getSimState */ public String getSimOperatorName() { - return getSimOperatorNameForPhone(getDefaultPhone()); + return getSimOperatorNameForPhone(getPhoneId()); } /** @@ -2198,7 +2201,7 @@ public class TelephonyManager { * Returns the ISO country code equivalent for the SIM provider's country code. */ public String getSimCountryIso() { - return getSimCountryIsoForPhone(getDefaultPhone()); + return getSimCountryIsoForPhone(getPhoneId()); } /** @@ -2754,7 +2757,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony != null) { return telephony - .getVisualVoicemailPackageName(mContext.getOpPackageName(), mSubId); + .getVisualVoicemailPackageName(mContext.getOpPackageName(), getSubId()); } } catch (RemoteException ex) { } catch (NullPointerException ex) { @@ -4057,35 +4060,67 @@ public class TelephonyManager { * subId is returned. Otherwise, the default subId will be returned. */ private int getSubId() { - if (mSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - return getDefaultSubscription(); + if (SubscriptionManager.isUsableSubIdValue(mSubId)) { + return mSubId; } - return mSubId; + return SubscriptionManager.getDefaultSubscriptionId(); + } + + /** + * Return an appropriate subscription ID for any situation. + * + * If this object has been created with {@link #createForSubscriptionId}, then the provided + * subId is returned. Otherwise, the preferred subId which is based on caller's context is + * returned. + * {@see SubscriptionManager#getDefaultDataSubscriptionId()} + * {@see SubscriptionManager#getDefaultVoiceSubscriptionId()} + * {@see SubscriptionManager#getDefaultSmsSubscriptionId()} + */ + private int getSubId(int preferredSubId) { + if (SubscriptionManager.isUsableSubIdValue(mSubId)) { + return mSubId; + } + return preferredSubId; } /** - * Returns Default subscription. + * Return an appropriate phone ID for any situation. + * + * If this object has been created with {@link #createForSubscriptionId}, then the phoneId + * associated with the provided subId is returned. Otherwise, the default phoneId associated + * with the default subId will be returned. */ - private static int getDefaultSubscription() { - return SubscriptionManager.getDefaultSubscriptionId(); + private int getPhoneId() { + return SubscriptionManager.getPhoneId(getSubId()); } /** - * Returns Default phone. + * Return an appropriate phone ID for any situation. + * + * If this object has been created with {@link #createForSubscriptionId}, then the phoneId + * associated with the provided subId is returned. Otherwise, return the phoneId associated + * with the preferred subId based on caller's context. + * {@see SubscriptionManager#getDefaultDataSubscriptionId()} + * {@see SubscriptionManager#getDefaultVoiceSubscriptionId()} + * {@see SubscriptionManager#getDefaultSmsSubscriptionId()} */ - private static int getDefaultPhone() { - return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubscriptionId()); + private int getPhoneId(int preferredSubId) { + return SubscriptionManager.getPhoneId(getSubId(preferredSubId)); } /** - * @return default SIM's slot index. If SIM is not inserted, return default SIM slot index. + * Return an appropriate slot index for any situation. + * + * if this object has been created with {@link #createForSubscriptionId}, then the slot index + * associated with the provided subId is returned. Otherwise, return the slot index associated + * with the default subId. + * If SIM is not inserted, return default SIM slot index. * * {@hide} */ @VisibleForTesting - public int getDefaultSim() { - int slotIndex = SubscriptionManager.getSlotIndex( - SubscriptionManager.getDefaultSubscriptionId()); + public int getSlotIndex() { + int slotIndex = SubscriptionManager.getSlotIndex(getSubId()); if (slotIndex == SubscriptionManager.SIM_NOT_INSERTED) { slotIndex = SubscriptionManager.DEFAULT_SIM_SLOT_INDEX; } @@ -4902,7 +4937,7 @@ public class TelephonyManager { /** @hide */ @SystemApi public List<String> getCarrierPackageNamesForIntent(Intent intent) { - return getCarrierPackageNamesForIntentAndPhone(intent, getDefaultPhone()); + return getCarrierPackageNamesForIntentAndPhone(intent, getPhoneId()); } /** @hide */ @@ -5164,7 +5199,7 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - telephony.handleUssdRequest(mSubId, ussdRequest, wrappedCallback); + telephony.handleUssdRequest(getSubId(), ussdRequest, wrappedCallback); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#sendUSSDCode", e); @@ -5184,7 +5219,8 @@ public class TelephonyManager { public boolean isConcurrentVoiceAndDataSupported() { try { ITelephony telephony = getITelephony(); - return (telephony == null ? false : telephony.isConcurrentVoiceAndDataAllowed(mSubId)); + return (telephony == null ? false : telephony.isConcurrentVoiceAndDataAllowed( + getSubId())); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#isConcurrentVoiceAndDataAllowed", e); } @@ -5321,6 +5357,8 @@ public class TelephonyManager { /** * Turns mobile data on or off. + * If this object has been created with {@link #createForSubscriptionId}, applies to the given + * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the @@ -5331,7 +5369,7 @@ public class TelephonyManager { * @see #hasCarrierPrivileges */ public void setDataEnabled(boolean enable) { - setDataEnabled(getSubId(), enable); + setDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable); } /** @hide */ @@ -5361,6 +5399,9 @@ public class TelephonyManager { /** * Returns whether mobile data is enabled or not. * + * If this object has been created with {@link #createForSubscriptionId}, applies to the given + * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * * <p>Requires one of the following permissions: * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE}, * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the @@ -5376,7 +5417,7 @@ public class TelephonyManager { */ @SuppressWarnings("deprecation") public boolean isDataEnabled() { - return getDataEnabled(getSubId()); + return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId())); } /** @@ -5626,7 +5667,7 @@ public class TelephonyManager { * @hide */ public void setSimOperatorNumeric(String numeric) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setSimOperatorNumericForPhone(phoneId, numeric); } @@ -5646,7 +5687,7 @@ public class TelephonyManager { * @hide */ public void setSimOperatorName(String name) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setSimOperatorNameForPhone(phoneId, name); } @@ -5666,7 +5707,7 @@ public class TelephonyManager { * @hide */ public void setSimCountryIso(String iso) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setSimCountryIsoForPhone(phoneId, iso); } @@ -5686,7 +5727,7 @@ public class TelephonyManager { * @hide */ public void setSimState(String state) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setSimStateForPhone(phoneId, state); } @@ -5711,7 +5752,7 @@ public class TelephonyManager { * @hide **/ public void setSimPowerState(boolean powerUp) { - setSimPowerStateForSlot(getDefaultSim(), powerUp); + setSimPowerStateForSlot(getSlotIndex(), powerUp); } /** @@ -5745,7 +5786,7 @@ public class TelephonyManager { * @hide */ public void setBasebandVersion(String version) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setBasebandVersionForPhone(phoneId, version); } @@ -5772,7 +5813,7 @@ public class TelephonyManager { * @hide */ public void setPhoneType(int type) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setPhoneType(phoneId, type); } @@ -5800,7 +5841,7 @@ public class TelephonyManager { * @hide */ public String getOtaSpNumberSchema(String defaultValue) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); return getOtaSpNumberSchemaForPhone(phoneId, defaultValue); } @@ -5831,7 +5872,7 @@ public class TelephonyManager { * @hide */ public boolean getSmsReceiveCapable(boolean defaultValue) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); return getSmsReceiveCapableForPhone(phoneId, defaultValue); } @@ -5862,7 +5903,7 @@ public class TelephonyManager { * @hide */ public boolean getSmsSendCapable(boolean defaultValue) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); return getSmsSendCapableForPhone(phoneId, defaultValue); } @@ -5890,7 +5931,7 @@ public class TelephonyManager { * @hide */ public void setNetworkOperatorName(String name) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setNetworkOperatorNameForPhone(phoneId, name); } @@ -5912,7 +5953,7 @@ public class TelephonyManager { * @hide */ public void setNetworkOperatorNumeric(String numeric) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setNetworkOperatorNumericForPhone(phoneId, numeric); } @@ -5932,7 +5973,7 @@ public class TelephonyManager { * @hide */ public void setNetworkRoaming(boolean isRoaming) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setNetworkRoamingForPhone(phoneId, isRoaming); } @@ -5956,7 +5997,7 @@ public class TelephonyManager { * @hide */ public void setNetworkCountryIso(String iso) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(); setNetworkCountryIsoForPhone(phoneId, iso); } @@ -5976,11 +6017,15 @@ public class TelephonyManager { /** * Set the network type currently in use on the device for data transmission. + * + * If this object has been created with {@link #createForSubscriptionId}, applies to the + * phoneId associated with the given subId. Otherwise, applies to the phoneId associated with + * {@link SubscriptionManager#getDefaultDataSubscriptionId()} * @param type the network type currently in use on the device for data transmission * @hide */ public void setDataNetworkType(int type) { - int phoneId = getDefaultPhone(); + int phoneId = getPhoneId(SubscriptionManager.getDefaultDataSubscriptionId()); setDataNetworkTypeForPhone(phoneId, type); } @@ -6200,7 +6245,7 @@ public class TelephonyManager { * @hide */ public String getAidForAppType(int appType) { - return getAidForAppType(getDefaultSubscription(), appType); + return getAidForAppType(getSubId(), appType); } /** @@ -6234,7 +6279,7 @@ public class TelephonyManager { * @hide */ public String getEsn() { - return getEsn(getDefaultSubscription()); + return getEsn(getSubId()); } /** @@ -6267,7 +6312,7 @@ public class TelephonyManager { * @hide */ public String getCdmaPrlVersion() { - return getCdmaPrlVersion(getDefaultSubscription()); + return getCdmaPrlVersion(getSubId()); } /** diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java index 82b3792a331c..bf5c42b8ca1c 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java @@ -19,6 +19,7 @@ package android.net.wifi.aware; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.NetworkSpecifier; import android.net.wifi.RttManager; import android.util.Log; @@ -250,8 +251,8 @@ public class DiscoverySession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * unencrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an unencrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -276,13 +277,13 @@ public class DiscoverySession { * request from only that peer. A RESPONDER may specify a {@code null} - * indicating that it will accept connection requests from any device. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) { + public NetworkSpecifier createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) { if (mTerminated) { Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session"); return null; @@ -302,8 +303,8 @@ public class DiscoverySession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -329,14 +330,14 @@ public class DiscoverySession { * {@link #createNetworkSpecifierOpen(PeerHandle)} API to * specify an open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierPassphrase(@Nullable PeerHandle peerHandle, - @NonNull String passphrase) { + public NetworkSpecifier createNetworkSpecifierPassphrase( + @Nullable PeerHandle peerHandle, @NonNull String passphrase) { if (passphrase == null || passphrase.length() == 0) { throw new IllegalArgumentException("Passphrase must not be null or empty"); } @@ -361,8 +362,8 @@ public class DiscoverySession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -389,8 +390,8 @@ public class DiscoverySession { * Passphrase or {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an * open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. @@ -398,7 +399,7 @@ public class DiscoverySession { * @hide */ @SystemApi - public String createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle, + public NetworkSpecifier createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle, @NonNull byte[] pmk) { if (pmk == null || pmk.length == 0) { throw new IllegalArgumentException("PMK must not be null or empty"); diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 4d3957aece91..3fcbd4b60259 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -24,6 +24,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; import android.net.wifi.RttManager; import android.os.Binder; import android.os.Bundle; @@ -31,7 +32,6 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.util.Base64; import android.util.Log; import android.util.SparseArray; @@ -39,9 +39,6 @@ import com.android.internal.annotations.GuardedBy; import libcore.util.HexEncoding; -import org.json.JSONException; -import org.json.JSONObject; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -129,65 +126,6 @@ public class WifiAwareManager { private static final boolean VDBG = false; // STOPSHIP if true /** - * Keys used to generate a Network Specifier for the Aware network request. The network - * specifier is formatted as a JSON string. - */ - - /** - * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk/passphrase optional - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_IB = 0; - - /** - * TYPE: in band, any peer: role, client_id, session_id, pmk/passphrase optional - * [only permitted for RESPONDER] - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1; - - /** - * TYPE: out-of-band: role, client_id, peer_mac, pmk/passphrase optional - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_OOB = 2; - - /** - * TYPE: out-of-band, any peer: role, client_id, pmk/passphrase optional - * [only permitted for RESPONDER] - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3; - - - /** @hide */ - public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_TYPE = "type"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_ROLE = "role"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_CLIENT_ID = "client_id"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_SESSION_ID = "session_id"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PEER_ID = "peer_id"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PMK = "pmk"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PASSPHRASE = "passphrase"; - - /** * Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed. * Use the {@link #isAvailable()} to query the current status. * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering @@ -483,7 +421,7 @@ public class WifiAwareManager { } /** @hide */ - public String createNetworkSpecifier(int clientId, int role, int sessionId, + public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId, PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId @@ -492,9 +430,6 @@ public class WifiAwareManager { + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); } - int type = (peerHandle == null) ? NETWORK_SPECIFIER_TYPE_IB_ANY_PEER - : NETWORK_SPECIFIER_TYPE_IB; - if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { throw new IllegalArgumentException( @@ -509,35 +444,20 @@ public class WifiAwareManager { } } - JSONObject json; - try { - json = new JSONObject(); - json.put(NETWORK_SPECIFIER_KEY_TYPE, type); - json.put(NETWORK_SPECIFIER_KEY_ROLE, role); - json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId); - json.put(NETWORK_SPECIFIER_KEY_SESSION_ID, sessionId); - if (peerHandle != null) { - json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId); - } - if (pmk == null) { - pmk = new byte[0]; - } - json.put(NETWORK_SPECIFIER_KEY_PMK, - Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT)); - if (passphrase == null) { - passphrase = new String(); - } - json.put(NETWORK_SPECIFIER_KEY_PASSPHRASE, passphrase); - - } catch (JSONException e) { - return ""; - } - - return json.toString(); + return new WifiAwareNetworkSpecifier( + (peerHandle == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER + : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, + role, + clientId, + sessionId, + peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID + null, // peerMac (not used in this method) + pmk, + passphrase); } /** @hide */ - public String createNetworkSpecifier(int clientId, @DataPathRole int role, + public NetworkSpecifier createNetworkSpecifier(int clientId, @DataPathRole int role, @Nullable byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { Log.v(TAG, "createNetworkSpecifier: role=" + role @@ -545,9 +465,6 @@ public class WifiAwareManager { + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); } - int type = (peer == null) ? - NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER : NETWORK_SPECIFIER_TYPE_OOB; - if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { throw new IllegalArgumentException( @@ -564,29 +481,16 @@ public class WifiAwareManager { throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address"); } - JSONObject json; - try { - json = new JSONObject(); - json.put(NETWORK_SPECIFIER_KEY_TYPE, type); - json.put(NETWORK_SPECIFIER_KEY_ROLE, role); - json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId); - if (peer != null) { - json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer))); - } - if (pmk == null) { - pmk = new byte[0]; - } - json.put(NETWORK_SPECIFIER_KEY_PMK, - Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT)); - if (passphrase == null) { - passphrase = new String(); - } - json.put(NETWORK_SPECIFIER_KEY_PASSPHRASE, passphrase); - } catch (JSONException e) { - return ""; - } - - return json.toString(); + return new WifiAwareNetworkSpecifier( + (peer == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER + : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB, + role, + clientId, + 0, // 0 is an invalid session ID + 0, // 0 is an invalid peer ID + peer, + pmk, + passphrase); } private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub { diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java new file mode 100644 index 000000000000..59934806f398 --- /dev/null +++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java @@ -0,0 +1,234 @@ +/* + * 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. + */ + +package android.net.wifi.aware; + +import android.net.NetworkSpecifier; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Network specifier object used to request a Wi-Fi Aware network. Apps do not create these objects + * directly but obtain them using + * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} or + * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)} or their secure (Passphrase) + * versions. + * + * @hide + */ +public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable { + /** + * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk/passphrase optional + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_IB = 0; + + /** + * TYPE: in band, any peer: role, client_id, session_id, pmk/passphrase optional + * [only permitted for RESPONDER] + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1; + + /** + * TYPE: out-of-band: role, client_id, peer_mac, pmk/passphrase optional + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_OOB = 2; + + /** + * TYPE: out-of-band, any peer: role, client_id, pmk/passphrase optional + * [only permitted for RESPONDER] + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3; + + /** @hide */ + public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER; + + /** + * One of the NETWORK_SPECIFIER_TYPE_* constants. The type of the network specifier object. + * @hide + */ + public final int type; + + /** + * The role of the device: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR or + * WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER. + * @hide + */ + public final int role; + + /** + * The client ID of the device. + * @hide + */ + public final int clientId; + + /** + * The session ID in which context to request a data-path. Only relevant for IB requests. + * @hide + */ + public final int sessionId; + + /** + * The peer ID of the device which the data-path should be connected to. Only relevant for + * IB requests (i.e. not IB_ANY_PEER or OOB*). + * @hide + */ + public final int peerId; + + /** + * The peer MAC address of the device which the data-path should be connected to. Only relevant + * for OB requests (i.e. not OOB_ANY_PEER or IB*). + * @hide + */ + public final byte[] peerMac; + + /** + * The PMK of the requested data-path. Can be null. Only one or none of pmk or passphrase should + * be specified. + * @hide + */ + public final byte[] pmk; + + /** + * The Passphrase of the requested data-path. Can be null. Only one or none of the pmk or + * passphrase should be specified. + * @hide + */ + public final String passphrase; + + /** @hide */ + public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId, + byte[] peerMac, byte[] pmk, String passphrase) { + this.type = type; + this.role = role; + this.clientId = clientId; + this.sessionId = sessionId; + this.peerId = peerId; + this.peerMac = peerMac; + this.pmk = pmk; + this.passphrase = passphrase; + } + + public static final Creator<WifiAwareNetworkSpecifier> CREATOR = + new Creator<WifiAwareNetworkSpecifier>() { + @Override + public WifiAwareNetworkSpecifier createFromParcel(Parcel in) { + return new WifiAwareNetworkSpecifier( + in.readInt(), // type + in.readInt(), // role + in.readInt(), // clientId + in.readInt(), // sessionId + in.readInt(), // peerId + in.createByteArray(), // peerMac + in.createByteArray(), // pmk + in.readString()); // passphrase + } + + @Override + public WifiAwareNetworkSpecifier[] newArray(int size) { + return new WifiAwareNetworkSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(type); + dest.writeInt(role); + dest.writeInt(clientId); + dest.writeInt(sessionId); + dest.writeInt(peerId); + dest.writeByteArray(peerMac); + dest.writeByteArray(pmk); + dest.writeString(passphrase); + } + + /** @hide */ + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + // MatchAllNetworkSpecifier is taken care in NetworkCapabilities#satisfiedBySpecifier. + return equals(other); + } + + /** @hide */ + @Override + public int hashCode() { + int result = 17; + + result = 31 * result + type; + result = 31 * result + role; + result = 31 * result + clientId; + result = 31 * result + sessionId; + result = 31 * result + peerId; + result = 31 * result + Arrays.hashCode(peerMac); + result = 31 * result + Arrays.hashCode(pmk); + result = 31 * result + Objects.hashCode(passphrase); + + return result; + } + + /** @hide */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof WifiAwareNetworkSpecifier)) { + return false; + } + + WifiAwareNetworkSpecifier lhs = (WifiAwareNetworkSpecifier) obj; + + return type == lhs.type + && role == lhs.role + && clientId == lhs.clientId + && sessionId == lhs.sessionId + && peerId == lhs.peerId + && Arrays.equals(peerMac, lhs.peerMac) + && Arrays.equals(pmk, lhs.pmk) + && Objects.equals(passphrase, lhs.passphrase); + } + + /** @hide */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("WifiAwareNetworkSpecifier ["); + sb.append("type=").append(type) + .append(", role=").append(role) + .append(", clientId=").append(clientId) + .append(", sessionId=").append(sessionId) + .append(", peerId=").append(peerId) + // masking potential PII (although low impact information) + .append(", peerMac=").append((peerMac == null) ? "<null>" : "<non-null>") + // masking PII + .append(", pmk=").append((pmk == null) ? "<null>" : "<non-null>") + // masking PII + .append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>") + .append("]"); + return sb.toString(); + } +} diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java index 895defb9a540..ac3a6bba052c 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java @@ -19,6 +19,7 @@ package android.net.wifi.aware; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.NetworkSpecifier; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -184,8 +185,8 @@ public class WifiAwareSession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * unencrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an unencrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -205,29 +206,29 @@ public class WifiAwareSession { * peer. A RESPONDER may specify a {@code null} - indicating that it will accept * connection requests from any device. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierOpen(@WifiAwareManager.DataPathRole int role, - @Nullable byte[] peer) { + public NetworkSpecifier createNetworkSpecifierOpen( + @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager"); - return ""; + return null; } if (mTerminated) { Log.e(TAG, "createNetworkSpecifierOpen: called after termination"); - return ""; + return null; } return mgr.createNetworkSpecifier(mClientId, role, peer, null, null); } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -247,22 +248,23 @@ public class WifiAwareSession { * the passphrase. Use {@link #createNetworkSpecifierOpen(int, byte[])} to * specify an open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierPassphrase(@WifiAwareManager.DataPathRole int role, - @Nullable byte[] peer, @NonNull String passphrase) { + public NetworkSpecifier createNetworkSpecifierPassphrase( + @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, + @NonNull String passphrase) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierPassphrase: called post GC on WifiAwareManager"); - return ""; + return null; } if (mTerminated) { Log.e(TAG, "createNetworkSpecifierPassphrase: called after termination"); - return ""; + return null; } if (passphrase == null || passphrase.length() == 0) { throw new IllegalArgumentException("Passphrase must not be null or empty"); @@ -271,8 +273,8 @@ public class WifiAwareSession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -294,8 +296,8 @@ public class WifiAwareSession { * Passphrase or {@link #createNetworkSpecifierOpen(int, byte[])} to specify an * open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. @@ -303,16 +305,16 @@ public class WifiAwareSession { * @hide */ @SystemApi - public String createNetworkSpecifierPmk(@WifiAwareManager.DataPathRole int role, - @Nullable byte[] peer, @NonNull byte[] pmk) { + public NetworkSpecifier createNetworkSpecifierPmk( + @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, @NonNull byte[] pmk) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager"); - return ""; + return null; } if (mTerminated) { Log.e(TAG, "createNetworkSpecifierPmk: called after termination"); - return ""; + return null; } if (pmk == null || pmk.length == 0) { throw new IllegalArgumentException("PMK must not be null or empty"); diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 830db22929e8..72a6a7a7b46b 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -34,11 +34,9 @@ import android.os.IBinder; import android.os.Parcel; import android.os.test.TestLooper; import android.test.suitebuilder.annotation.SmallTest; -import android.util.Base64; import libcore.util.HexEncoding; -import org.json.JSONObject; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -959,8 +957,6 @@ public class WifiAwareManagerTest { final ConfigRequest configRequest = new ConfigRequest.Builder().build(); final PublishConfig publishConfig = new PublishConfig.Builder().build(); - String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT); - ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass( WifiAwareSession.class); ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor @@ -991,51 +987,37 @@ public class WifiAwareManagerTest { inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture()); // (3) request an open (unencrypted) network specifier from the session - String networkSpecifier = publishSession.getValue().createNetworkSpecifierOpen(peerHandle); + WifiAwareNetworkSpecifier ns = + (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierOpen( + peerHandle); // validate format - JSONObject jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("session_id", sessionId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); - collector.checkThat("peer_id", peerHandle.peerId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); + collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); // (4) request an encrypted (PMK) network specifier from the session - networkSpecifier = publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk); + ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk( + peerHandle, pmk); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("session_id", sessionId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); - collector.checkThat("peer_id", peerHandle.peerId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); - collector.checkThat("pmk", pmkB64 , - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); + collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); + collector.checkThat("pmk", pmk , equalTo(ns.pmk)); // (5) request an encrypted (Passphrase) network specifier from the session - networkSpecifier = publishSession.getValue().createNetworkSpecifierPassphrase(peerHandle, - passphrase); + ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPassphrase( + peerHandle, passphrase); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("session_id", sessionId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); - collector.checkThat("peer_id", peerHandle.peerId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); - collector.checkThat("passphrase", passphrase, - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PASSPHRASE))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); + collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); + collector.checkThat("passphrase", passphrase, equalTo(ns.passphrase)); verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService, mockPublishSession, mockRttListener); @@ -1054,8 +1036,6 @@ public class WifiAwareManagerTest { final byte[] pmk = "Some arbitrary pmk data".getBytes(); final String passphrase = "A really bad password"; - String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT); - ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass( WifiAwareSession.class); ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor @@ -1074,47 +1054,32 @@ public class WifiAwareManagerTest { WifiAwareSession session = sessionCaptor.getValue(); // (2) request an open (unencrypted) direct network specifier - String networkSpecifier = session.createNetworkSpecifierOpen(role, someMac); + WifiAwareNetworkSpecifier ns = + (WifiAwareNetworkSpecifier) session.createNetworkSpecifierOpen(role, someMac); // validate format - JSONObject jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( - jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), - false))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); // (3) request an encrypted (PMK) direct network specifier - networkSpecifier = session.createNetworkSpecifierPmk(role, someMac, pmk); + ns = (WifiAwareNetworkSpecifier) session.createNetworkSpecifierPmk(role, someMac, pmk); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( - jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), - false))); - collector.checkThat("pmk", pmkB64, - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); + collector.checkThat("pmk", pmk, equalTo(ns.pmk)); // (4) request an encrypted (Passphrase) direct network specifier - networkSpecifier = session.createNetworkSpecifierPassphrase(role, someMac, passphrase); + ns = (WifiAwareNetworkSpecifier) session.createNetworkSpecifierPassphrase(role, someMac, + passphrase); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( - jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), - false))); - collector.checkThat("passphrase", passphrase, - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PASSPHRASE))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); + collector.checkThat("passphrase", passphrase, equalTo(ns.passphrase)); verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService, mockPublishSession, mockRttListener); |