diff options
155 files changed, 4399 insertions, 2986 deletions
diff --git a/api/current.txt b/api/current.txt index 79f88aacebc6..5697b3970851 100644 --- a/api/current.txt +++ b/api/current.txt @@ -211,6 +211,7 @@ package android { ctor public R.attr(); field public static final int __removed1 = 16844099; // 0x1010543 field public static final int __removed2 = 16844104; // 0x1010548 + field public static final int __removed3 = 16844116; // 0x1010554 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -313,7 +314,6 @@ package android { field public static final int autoUrlDetect = 16843404; // 0x101028c field public static final int autoVerify = 16844014; // 0x10104ee field public static final int autofillHints = 16844121; // 0x1010559 - field public static final int autofillMode = 16844116; // 0x1010554 field public static final int background = 16842964; // 0x10100d4 field public static final int backgroundDimAmount = 16842802; // 0x1010032 field public static final int backgroundDimEnabled = 16843295; // 0x101021f @@ -3615,6 +3615,7 @@ package android.app { method public android.net.Uri getReferrer(); method public int getRequestedOrientation(); method public final android.view.SearchEvent getSearchEvent(); + method public long getStartInitiatedTime(); method public int getTaskId(); method public final java.lang.CharSequence getTitle(); method public final int getTitleColor(); @@ -3941,7 +3942,8 @@ package android.app { field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d field public static final int IMPORTANCE_GONE = 1000; // 0x3e8 - field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82 + field public static final int IMPORTANCE_PERCEPTIBLE = 230; // 0xe6 + field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82 field public static final int IMPORTANCE_SERVICE = 300; // 0x12c field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96 field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8 @@ -6090,6 +6092,17 @@ package android.app { method public void onDetached(); } + public final class WallpaperColors implements android.os.Parcelable { + ctor public WallpaperColors(android.os.Parcel); + ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>); + ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>, boolean); + method public int describeContents(); + method public java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>> getColors(); + method public boolean supportsDarkText(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR; + } + public final class WallpaperInfo implements android.os.Parcelable { ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public int describeContents(); @@ -6112,6 +6125,8 @@ package android.app { } public class WallpaperManager { + method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener); + method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler); method public void clear() throws java.io.IOException; method public void clear(int) throws java.io.IOException; method public void clearWallpaperOffsets(android.os.IBinder); @@ -6126,6 +6141,7 @@ package android.app { method public android.graphics.drawable.Drawable getDrawable(); method public android.graphics.drawable.Drawable getFastDrawable(); method public static android.app.WallpaperManager getInstance(android.content.Context); + method public android.app.WallpaperColors getWallpaperColors(int); method public android.os.ParcelFileDescriptor getWallpaperFile(int); method public int getWallpaperId(int); method public android.app.WallpaperInfo getWallpaperInfo(); @@ -6134,6 +6150,7 @@ package android.app { method public boolean isWallpaperSupported(); method public android.graphics.drawable.Drawable peekDrawable(); method public android.graphics.drawable.Drawable peekFastDrawable(); + method public void removeOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener); method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle); method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException; method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException; @@ -6158,6 +6175,10 @@ package android.app { field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview"; } + public static abstract interface WallpaperManager.OnColorsChangedListener { + method public abstract void onColorsChanged(android.app.WallpaperColors, int); + } + } package android.app.admin { @@ -6793,6 +6814,7 @@ package android.app.job { field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 + field public static final int NETWORK_TYPE_METERED = 4; // 0x4 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 @@ -6867,6 +6889,14 @@ package android.app.job { field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; } + public abstract class JobServiceEngine { + ctor public JobServiceEngine(android.content.Context); + method public final android.os.IBinder getBinder(); + method public final void jobFinished(android.app.job.JobParameters, boolean); + method public abstract boolean onStartJob(android.app.job.JobParameters); + method public abstract boolean onStopJob(android.app.job.JobParameters); + } + public final class JobWorkItem implements android.os.Parcelable { ctor public JobWorkItem(android.content.Intent); ctor public JobWorkItem(android.os.Parcel); @@ -8067,7 +8097,12 @@ package android.bluetooth.le { method public void flushPendingScanResults(android.bluetooth.le.ScanCallback); method public void startScan(android.bluetooth.le.ScanCallback); method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback); + method public int startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.app.PendingIntent); method public void stopScan(android.bluetooth.le.ScanCallback); + method public void stopScan(android.app.PendingIntent); + field public static final java.lang.String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; + field public static final java.lang.String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; + field public static final java.lang.String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT"; } public final class PeriodicAdvertisingParameters implements android.os.Parcelable { @@ -8242,7 +8277,8 @@ package android.companion { method public android.companion.BluetoothLEDeviceFilter build(); method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern); method public android.companion.BluetoothLEDeviceFilter.Builder setRawDataFilter(byte[], byte[]); - method public android.companion.BluetoothLEDeviceFilter.Builder setRename(java.lang.String, java.lang.String, int, int, boolean); + method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromBytes(java.lang.String, java.lang.String, int, int, boolean); + method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromName(java.lang.String, java.lang.String, int, int); method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter); } @@ -8250,6 +8286,8 @@ package android.companion { method public void associate(android.companion.AssociationRequest, android.companion.CompanionDeviceManager.Callback, android.os.Handler); method public void disassociate(java.lang.String); method public java.util.List<java.lang.String> getAssociations(); + method public boolean hasNotificationAccess(android.content.ComponentName); + method public void requestNotificationAccess(android.content.ComponentName); field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE"; } @@ -9322,7 +9360,6 @@ package android.content { field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED"; field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE"; field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE"; - field public static final deprecated java.lang.String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR"; field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL"; field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON"; field public static final java.lang.String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING"; @@ -12532,6 +12569,7 @@ package android.graphics { field public boolean inJustDecodeBounds; field public boolean inMutable; field public deprecated boolean inPreferQualityOverSpeed; + field public android.graphics.ColorSpace inPreferredColorSpace; field public android.graphics.Bitmap.Config inPreferredConfig; field public boolean inPremultiplied; field public deprecated boolean inPurgeable; @@ -21868,7 +21906,7 @@ package android.media { method public deprecated java.nio.ByteBuffer[] getInputBuffers(); method public final android.media.MediaFormat getInputFormat(); method public android.media.Image getInputImage(int); - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public final java.lang.String getName(); method public java.nio.ByteBuffer getOutputBuffer(int); method public deprecated java.nio.ByteBuffer[] getOutputBuffers(); @@ -21966,6 +22004,19 @@ package android.media { method public void set(int, int); } + public static final class MediaCodec.MetricsConstants { + field public static final java.lang.String CODEC = "android.media.mediacodec.codec"; + field public static final java.lang.String ENCODER = "android.media.mediacodec.encoder"; + field public static final java.lang.String HEIGHT = "android.media.mediacodec.height"; + field public static final java.lang.String MIME_TYPE = "android.media.mediacodec.mime"; + field public static final java.lang.String MODE = "android.media.mediacodec.mode"; + field public static final java.lang.String MODE_AUDIO = "audio"; + field public static final java.lang.String MODE_VIDEO = "video"; + field public static final java.lang.String ROTATION = "android.media.mediacodec.rotation"; + field public static final java.lang.String SECURE = "android.media.mediacodec.secure"; + field public static final java.lang.String WIDTH = "android.media.mediacodec.width"; + } + public static abstract interface MediaCodec.OnFrameRenderedListener { method public abstract void onFrameRendered(android.media.MediaCodec, long, long); } @@ -22421,7 +22472,7 @@ package android.media { method public long getCachedDuration(); method public android.media.MediaExtractor.CasInfo getCasInfo(int); method public android.media.DrmInitData getDrmInitData(); - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public java.util.Map<java.util.UUID, byte[]> getPsshInfo(); method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo); method public int getSampleFlags(); @@ -22456,6 +22507,12 @@ package android.media { method public int getSystemId(); } + public static final class MediaExtractor.MetricsConstants { + field public static final java.lang.String FORMAT = "android.media.mediaextractor.fmt"; + field public static final java.lang.String MIME_TYPE = "android.media.mediaextractor.mime"; + field public static final java.lang.String TRACKS = "android.media.mediaextractor.ntrk"; + } + public final class MediaFormat { ctor public MediaFormat(); method public final boolean containsKey(java.lang.String); @@ -22681,69 +22738,6 @@ package android.media { field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0 } - public final class MediaMetricsSet { - method public double getDouble(java.lang.String, double); - method public int getInt(java.lang.String, int); - method public long getLong(java.lang.String, long); - method public java.lang.String getString(java.lang.String, java.lang.String); - method public boolean isEmpty(); - method public java.util.Set<java.lang.String> keySet(); - method public int size(); - } - - public static final class MediaMetricsSet.MediaCodec { - field public static final java.lang.String KEY_CODEC = "android.media.mediacodec.codec"; - field public static final java.lang.String KEY_ENCODER = "android.media.mediacodec.encoder"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediacodec.height"; - field public static final java.lang.String KEY_MIME = "android.media.mediacodec.mime"; - field public static final java.lang.String KEY_MODE = "android.media.mediacodec.mode"; - field public static final java.lang.String KEY_ROTATION = "android.media.mediacodec.rotation"; - field public static final java.lang.String KEY_SECURE = "android.media.mediacodec.secure"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediacodec.width"; - field public static final java.lang.String MODE_AUDIO = "audio"; - field public static final java.lang.String MODE_VIDEO = "video"; - } - - public static final class MediaMetricsSet.MediaExtractor { - field public static final java.lang.String KEY_FORMAT = "android.media.mediaextractor.fmt"; - field public static final java.lang.String KEY_MIME = "android.media.mediaextractor.mime"; - field public static final java.lang.String KEY_TRACKS = "android.media.mediaextractor.ntrk"; - } - - public static final class MediaMetricsSet.MediaPlayer { - field public static final java.lang.String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; - field public static final java.lang.String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec"; - field public static final java.lang.String KEY_DURATION = "android.media.mediaplayer.durationMs"; - field public static final java.lang.String KEY_ERRORS = "android.media.mediaplayer.err"; - field public static final java.lang.String KEY_ERROR_CODE = "android.media.mediaplayer.errcode"; - field public static final java.lang.String KEY_FRAMES = "android.media.mediaplayer.frames"; - field public static final java.lang.String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediaplayer.height"; - field public static final java.lang.String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime"; - field public static final java.lang.String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime"; - field public static final java.lang.String KEY_PLAYING = "android.media.mediaplayer.playingMs"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediaplayer.width"; - } - - public static final class MediaMetricsSet.MediaRecorder { - field public static final java.lang.String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; - field public static final java.lang.String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; - field public static final java.lang.String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; - field public static final java.lang.String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; - field public static final java.lang.String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; - field public static final java.lang.String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; - field public static final java.lang.String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediarecorder.height"; - field public static final java.lang.String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; - field public static final java.lang.String KEY_ROTATION = "android.media.mediarecorder.rotation"; - field public static final java.lang.String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; - field public static final java.lang.String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; - field public static final java.lang.String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; - field public static final java.lang.String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; - field public static final java.lang.String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediarecorder.width"; - } - public final class MediaMuxer { ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException; ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException; @@ -22782,7 +22776,7 @@ package android.media { 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.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); @@ -22877,6 +22871,21 @@ package android.media { method public java.util.UUID[] getSupportedSchemes(); } + public static final class MediaPlayer.MetricsConstants { + field public static final java.lang.String CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; + field public static final java.lang.String CODEC_VIDEO = "android.media.mediaplayer.video.codec"; + field public static final java.lang.String DURATION = "android.media.mediaplayer.durationMs"; + field public static final java.lang.String ERRORS = "android.media.mediaplayer.err"; + field public static final java.lang.String ERROR_CODE = "android.media.mediaplayer.errcode"; + field public static final java.lang.String FRAMES = "android.media.mediaplayer.frames"; + field public static final java.lang.String FRAMES_DROPPED = "android.media.mediaplayer.dropped"; + field public static final java.lang.String HEIGHT = "android.media.mediaplayer.height"; + field public static final java.lang.String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime"; + field public static final java.lang.String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime"; + field public static final java.lang.String PLAYING = "android.media.mediaplayer.playingMs"; + field public static final java.lang.String WIDTH = "android.media.mediaplayer.width"; + } + public static final class MediaPlayer.NoDrmSchemeException extends android.media.MediaDrmException { ctor public MediaPlayer.NoDrmSchemeException(java.lang.String); } @@ -22951,7 +22960,7 @@ package android.media { ctor public MediaRecorder(); method public static final int getAudioSourceMax(); method public int getMaxAmplitude() throws java.lang.IllegalStateException; - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public android.view.Surface getSurface(); method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; @@ -23019,6 +23028,25 @@ package android.media { field public static final int VOICE_UPLINK = 2; // 0x2 } + public static final class MediaRecorder.MetricsConstants { + field public static final java.lang.String AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; + field public static final java.lang.String AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; + field public static final java.lang.String AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; + field public static final java.lang.String AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; + field public static final java.lang.String CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; + field public static final java.lang.String CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; + field public static final java.lang.String FRAMERATE = "android.media.mediarecorder.frame-rate"; + field public static final java.lang.String HEIGHT = "android.media.mediarecorder.height"; + field public static final java.lang.String MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; + field public static final java.lang.String ROTATION = "android.media.mediarecorder.rotation"; + field public static final java.lang.String VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; + field public static final java.lang.String VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; + field public static final java.lang.String VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; + field public static final java.lang.String VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; + field public static final java.lang.String VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; + field public static final java.lang.String WIDTH = "android.media.mediarecorder.width"; + } + public static abstract interface MediaRecorder.OnErrorListener { method public abstract void onError(android.media.MediaRecorder, int, int); } @@ -25520,22 +25548,25 @@ package android.net { method public java.lang.String getName(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); - field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)"; - field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)"; + field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)"; + field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)"; + field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)"; + field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)"; + field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)"; field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR; + field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)"; } 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 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 } @@ -25775,6 +25806,10 @@ package android.net { method public android.net.NetworkRequest.Builder removeCapability(int); method public android.net.NetworkRequest.Builder removeTransportType(int); method public android.net.NetworkRequest.Builder setNetworkSpecifier(java.lang.String); + method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); + } + + public abstract class NetworkSpecifier { } public class ParseException extends java.lang.RuntimeException { @@ -37028,8 +37063,10 @@ package android.service.autofill { method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); - method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback); - method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback); + method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback); + method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback); + method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback); + method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback); field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService"; field public static final java.lang.String SERVICE_META_DATA = "android.autofill"; } @@ -37054,6 +37091,25 @@ package android.service.autofill { method public void onSuccess(android.service.autofill.FillResponse); } + public final class FillContext implements android.os.Parcelable { + method public int describeContents(); + method public int getRequestId(); + method public android.app.assist.AssistStructure getStructure(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR; + } + + public final class FillRequest implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public int getFlags(); + method public int getId(); + method public android.app.assist.AssistStructure getStructure(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR; + field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1 + } + public final class FillResponse implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); @@ -37065,7 +37121,8 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset); method public android.service.autofill.FillResponse build(); 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 setExtras(android.os.Bundle); + 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 setSaveInfo(android.service.autofill.SaveInfo); } @@ -37094,6 +37151,14 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); } + public final class SaveRequest implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public java.util.List<android.service.autofill.FillContext> getFillContexts(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR; + } + } package android.service.carrier { @@ -37727,10 +37792,12 @@ package android.service.wallpaper { method public int getDesiredMinimumHeight(); method public int getDesiredMinimumWidth(); method public android.view.SurfaceHolder getSurfaceHolder(); + method public void invalidateColors(); method public boolean isPreview(); method public boolean isVisible(); method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); + method public android.app.WallpaperColors onComputeWallpaperColors(); method public void onCreate(android.view.SurfaceHolder); method public void onDesiredSizeChanged(int, int); method public void onDestroy(); @@ -45361,7 +45428,6 @@ package android.view { method public android.view.animation.Animation getAnimation(); method public android.os.IBinder getApplicationWindowToken(); method public java.lang.String[] getAutofillHints(); - method public int getAutofillMode(); method public int getAutofillType(); method public android.view.autofill.AutofillValue getAutofillValue(); method public android.graphics.drawable.Drawable getBackground(); @@ -45450,7 +45516,6 @@ package android.view { method public float getPivotX(); method public float getPivotY(); method public android.view.PointerIcon getPointerIcon(); - method public int getResolvedAutofillMode(); method public android.content.res.Resources getResources(); method public final boolean getRevealOnFocusHint(); method public final int getRight(); @@ -45683,7 +45748,6 @@ package android.view { method public void setAlpha(float); method public void setAnimation(android.view.animation.Animation); method public void setAutofillHints(java.lang.String...); - method public void setAutofillMode(int); method public void setBackground(android.graphics.drawable.Drawable); method public void setBackgroundColor(int); method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable); @@ -45839,9 +45903,6 @@ package android.view { field public static final java.lang.String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; field public static final java.lang.String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; field public static final java.lang.String AUTOFILL_HINT_USERNAME = "username"; - field public static final int AUTOFILL_MODE_AUTO = 1; // 0x1 - field public static final int AUTOFILL_MODE_INHERIT = 0; // 0x0 - field public static final int AUTOFILL_MODE_MANUAL = 2; // 0x2 field public static final int AUTOFILL_TYPE_DATE = 4; // 0x4 field public static final int AUTOFILL_TYPE_LIST = 3; // 0x3 field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0 @@ -46409,7 +46470,6 @@ package android.view { method public abstract int getLayoutDirection(); method public abstract android.view.ViewParent getParent(); method public abstract android.view.ViewParent getParentForAccessibility(); - method public default int getResolvedAutofillMode(); method public abstract int getTextAlignment(); method public abstract int getTextDirection(); method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect); @@ -47796,7 +47856,7 @@ package android.view.autofill { field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE"; field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT"; field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS"; - field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1 + field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1 } public static abstract class AutofillManager.AutofillCallback { diff --git a/api/system-current.txt b/api/system-current.txt index 83855e66a89d..8b2ac55b3374 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -329,6 +329,7 @@ package android { ctor public R.attr(); field public static final int __removed1 = 16844099; // 0x1010543 field public static final int __removed2 = 16844104; // 0x1010548 + field public static final int __removed3 = 16844116; // 0x1010554 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -431,7 +432,6 @@ package android { field public static final int autoUrlDetect = 16843404; // 0x101028c field public static final int autoVerify = 16844014; // 0x10104ee field public static final int autofillHints = 16844121; // 0x1010559 - field public static final int autofillMode = 16844116; // 0x1010554 field public static final int background = 16842964; // 0x10100d4 field public static final int backgroundDimAmount = 16842802; // 0x1010032 field public static final int backgroundDimEnabled = 16843295; // 0x101021f @@ -3743,6 +3743,7 @@ package android.app { method public android.net.Uri getReferrer(); method public int getRequestedOrientation(); method public final android.view.SearchEvent getSearchEvent(); + method public long getStartInitiatedTime(); method public int getTaskId(); method public final java.lang.CharSequence getTitle(); method public final int getTitleColor(); @@ -4087,7 +4088,8 @@ package android.app { field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d field public static final int IMPORTANCE_GONE = 1000; // 0x3e8 - field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82 + field public static final int IMPORTANCE_PERCEPTIBLE = 230; // 0xe6 + field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82 field public static final int IMPORTANCE_SERVICE = 300; // 0x12c field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96 field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8 @@ -6294,6 +6296,17 @@ package android.app { method public void setPersistentVrModeEnabled(boolean); } + public final class WallpaperColors implements android.os.Parcelable { + ctor public WallpaperColors(android.os.Parcel); + ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>); + ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>, boolean); + method public int describeContents(); + method public java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>> getColors(); + method public boolean supportsDarkText(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR; + } + public final class WallpaperInfo implements android.os.Parcelable { ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public int describeContents(); @@ -6316,6 +6329,8 @@ package android.app { } public class WallpaperManager { + method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener); + method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler); method public void clear() throws java.io.IOException; method public void clear(int) throws java.io.IOException; method public void clearWallpaper(); @@ -6332,6 +6347,7 @@ package android.app { method public android.graphics.drawable.Drawable getDrawable(); method public android.graphics.drawable.Drawable getFastDrawable(); method public static android.app.WallpaperManager getInstance(android.content.Context); + method public android.app.WallpaperColors getWallpaperColors(int); method public android.os.ParcelFileDescriptor getWallpaperFile(int); method public int getWallpaperId(int); method public android.app.WallpaperInfo getWallpaperInfo(); @@ -6340,6 +6356,7 @@ package android.app { method public boolean isWallpaperSupported(); method public android.graphics.drawable.Drawable peekDrawable(); method public android.graphics.drawable.Drawable peekFastDrawable(); + method public void removeOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener); method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle); method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException; method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException; @@ -6367,6 +6384,10 @@ package android.app { field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview"; } + public static abstract interface WallpaperManager.OnColorsChangedListener { + method public abstract void onColorsChanged(android.app.WallpaperColors, int); + } + } package android.app.admin { @@ -7226,6 +7247,7 @@ package android.app.job { field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 + field public static final int NETWORK_TYPE_METERED = 4; // 0x4 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 @@ -7301,6 +7323,14 @@ package android.app.job { field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; } + public abstract class JobServiceEngine { + ctor public JobServiceEngine(android.content.Context); + method public final android.os.IBinder getBinder(); + method public final void jobFinished(android.app.job.JobParameters, boolean); + method public abstract boolean onStartJob(android.app.job.JobParameters); + method public abstract boolean onStopJob(android.app.job.JobParameters); + } + public final class JobWorkItem implements android.os.Parcelable { ctor public JobWorkItem(android.content.Intent); ctor public JobWorkItem(android.os.Parcel); @@ -8539,10 +8569,15 @@ package android.bluetooth.le { method public void flushPendingScanResults(android.bluetooth.le.ScanCallback); method public void startScan(android.bluetooth.le.ScanCallback); method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback); + method public int startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.app.PendingIntent); method public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback); method public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback); method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback); method public void stopScan(android.bluetooth.le.ScanCallback); + method public void stopScan(android.app.PendingIntent); + field public static final java.lang.String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; + field public static final java.lang.String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; + field public static final java.lang.String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT"; } public final class PeriodicAdvertisingParameters implements android.os.Parcelable { @@ -8736,7 +8771,8 @@ package android.companion { method public android.companion.BluetoothLEDeviceFilter build(); method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern); method public android.companion.BluetoothLEDeviceFilter.Builder setRawDataFilter(byte[], byte[]); - method public android.companion.BluetoothLEDeviceFilter.Builder setRename(java.lang.String, java.lang.String, int, int, boolean); + method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromBytes(java.lang.String, java.lang.String, int, int, boolean); + method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromName(java.lang.String, java.lang.String, int, int); method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter); } @@ -8744,6 +8780,8 @@ package android.companion { method public void associate(android.companion.AssociationRequest, android.companion.CompanionDeviceManager.Callback, android.os.Handler); method public void disassociate(java.lang.String); method public java.util.List<java.lang.String> getAssociations(); + method public boolean hasNotificationAccess(android.content.ComponentName); + method public void requestNotificationAccess(android.content.ComponentName); field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE"; } @@ -13302,6 +13340,7 @@ package android.graphics { field public boolean inJustDecodeBounds; field public boolean inMutable; field public deprecated boolean inPreferQualityOverSpeed; + field public android.graphics.ColorSpace inPreferredColorSpace; field public android.graphics.Bitmap.Config inPreferredConfig; field public boolean inPremultiplied; field public deprecated boolean inPurgeable; @@ -23700,7 +23739,7 @@ package android.media { method public deprecated java.nio.ByteBuffer[] getInputBuffers(); method public final android.media.MediaFormat getInputFormat(); method public android.media.Image getInputImage(int); - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public final java.lang.String getName(); method public java.nio.ByteBuffer getOutputBuffer(int); method public deprecated java.nio.ByteBuffer[] getOutputBuffers(); @@ -23798,6 +23837,19 @@ package android.media { method public void set(int, int); } + public static final class MediaCodec.MetricsConstants { + field public static final java.lang.String CODEC = "android.media.mediacodec.codec"; + field public static final java.lang.String ENCODER = "android.media.mediacodec.encoder"; + field public static final java.lang.String HEIGHT = "android.media.mediacodec.height"; + field public static final java.lang.String MIME_TYPE = "android.media.mediacodec.mime"; + field public static final java.lang.String MODE = "android.media.mediacodec.mode"; + field public static final java.lang.String MODE_AUDIO = "audio"; + field public static final java.lang.String MODE_VIDEO = "video"; + field public static final java.lang.String ROTATION = "android.media.mediacodec.rotation"; + field public static final java.lang.String SECURE = "android.media.mediacodec.secure"; + field public static final java.lang.String WIDTH = "android.media.mediacodec.width"; + } + public static abstract interface MediaCodec.OnFrameRenderedListener { method public abstract void onFrameRendered(android.media.MediaCodec, long, long); } @@ -24253,7 +24305,7 @@ package android.media { method public long getCachedDuration(); method public android.media.MediaExtractor.CasInfo getCasInfo(int); method public android.media.DrmInitData getDrmInitData(); - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public java.util.Map<java.util.UUID, byte[]> getPsshInfo(); method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo); method public int getSampleFlags(); @@ -24288,6 +24340,12 @@ package android.media { method public int getSystemId(); } + public static final class MediaExtractor.MetricsConstants { + field public static final java.lang.String FORMAT = "android.media.mediaextractor.fmt"; + field public static final java.lang.String MIME_TYPE = "android.media.mediaextractor.mime"; + field public static final java.lang.String TRACKS = "android.media.mediaextractor.ntrk"; + } + public final class MediaFormat { ctor public MediaFormat(); method public final boolean containsKey(java.lang.String); @@ -24513,69 +24571,6 @@ package android.media { field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0 } - public final class MediaMetricsSet { - method public double getDouble(java.lang.String, double); - method public int getInt(java.lang.String, int); - method public long getLong(java.lang.String, long); - method public java.lang.String getString(java.lang.String, java.lang.String); - method public boolean isEmpty(); - method public java.util.Set<java.lang.String> keySet(); - method public int size(); - } - - public static final class MediaMetricsSet.MediaCodec { - field public static final java.lang.String KEY_CODEC = "android.media.mediacodec.codec"; - field public static final java.lang.String KEY_ENCODER = "android.media.mediacodec.encoder"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediacodec.height"; - field public static final java.lang.String KEY_MIME = "android.media.mediacodec.mime"; - field public static final java.lang.String KEY_MODE = "android.media.mediacodec.mode"; - field public static final java.lang.String KEY_ROTATION = "android.media.mediacodec.rotation"; - field public static final java.lang.String KEY_SECURE = "android.media.mediacodec.secure"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediacodec.width"; - field public static final java.lang.String MODE_AUDIO = "audio"; - field public static final java.lang.String MODE_VIDEO = "video"; - } - - public static final class MediaMetricsSet.MediaExtractor { - field public static final java.lang.String KEY_FORMAT = "android.media.mediaextractor.fmt"; - field public static final java.lang.String KEY_MIME = "android.media.mediaextractor.mime"; - field public static final java.lang.String KEY_TRACKS = "android.media.mediaextractor.ntrk"; - } - - public static final class MediaMetricsSet.MediaPlayer { - field public static final java.lang.String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; - field public static final java.lang.String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec"; - field public static final java.lang.String KEY_DURATION = "android.media.mediaplayer.durationMs"; - field public static final java.lang.String KEY_ERRORS = "android.media.mediaplayer.err"; - field public static final java.lang.String KEY_ERROR_CODE = "android.media.mediaplayer.errcode"; - field public static final java.lang.String KEY_FRAMES = "android.media.mediaplayer.frames"; - field public static final java.lang.String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediaplayer.height"; - field public static final java.lang.String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime"; - field public static final java.lang.String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime"; - field public static final java.lang.String KEY_PLAYING = "android.media.mediaplayer.playingMs"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediaplayer.width"; - } - - public static final class MediaMetricsSet.MediaRecorder { - field public static final java.lang.String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; - field public static final java.lang.String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; - field public static final java.lang.String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; - field public static final java.lang.String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; - field public static final java.lang.String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; - field public static final java.lang.String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; - field public static final java.lang.String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediarecorder.height"; - field public static final java.lang.String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; - field public static final java.lang.String KEY_ROTATION = "android.media.mediarecorder.rotation"; - field public static final java.lang.String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; - field public static final java.lang.String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; - field public static final java.lang.String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; - field public static final java.lang.String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; - field public static final java.lang.String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediarecorder.width"; - } - public final class MediaMuxer { ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException; ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException; @@ -24614,7 +24609,7 @@ package android.media { 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.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); @@ -24709,6 +24704,21 @@ package android.media { method public java.util.UUID[] getSupportedSchemes(); } + public static final class MediaPlayer.MetricsConstants { + field public static final java.lang.String CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; + field public static final java.lang.String CODEC_VIDEO = "android.media.mediaplayer.video.codec"; + field public static final java.lang.String DURATION = "android.media.mediaplayer.durationMs"; + field public static final java.lang.String ERRORS = "android.media.mediaplayer.err"; + field public static final java.lang.String ERROR_CODE = "android.media.mediaplayer.errcode"; + field public static final java.lang.String FRAMES = "android.media.mediaplayer.frames"; + field public static final java.lang.String FRAMES_DROPPED = "android.media.mediaplayer.dropped"; + field public static final java.lang.String HEIGHT = "android.media.mediaplayer.height"; + field public static final java.lang.String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime"; + field public static final java.lang.String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime"; + field public static final java.lang.String PLAYING = "android.media.mediaplayer.playingMs"; + field public static final java.lang.String WIDTH = "android.media.mediaplayer.width"; + } + public static final class MediaPlayer.NoDrmSchemeException extends android.media.MediaDrmException { ctor public MediaPlayer.NoDrmSchemeException(java.lang.String); } @@ -24783,7 +24793,7 @@ package android.media { ctor public MediaRecorder(); method public static final int getAudioSourceMax(); method public int getMaxAmplitude() throws java.lang.IllegalStateException; - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public android.view.Surface getSurface(); method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; @@ -24853,6 +24863,25 @@ package android.media { field public static final int VOICE_UPLINK = 2; // 0x2 } + public static final class MediaRecorder.MetricsConstants { + field public static final java.lang.String AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; + field public static final java.lang.String AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; + field public static final java.lang.String AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; + field public static final java.lang.String AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; + field public static final java.lang.String CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; + field public static final java.lang.String CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; + field public static final java.lang.String FRAMERATE = "android.media.mediarecorder.frame-rate"; + field public static final java.lang.String HEIGHT = "android.media.mediarecorder.height"; + field public static final java.lang.String MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; + field public static final java.lang.String ROTATION = "android.media.mediarecorder.rotation"; + field public static final java.lang.String VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; + field public static final java.lang.String VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; + field public static final java.lang.String VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; + field public static final java.lang.String VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; + field public static final java.lang.String VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; + field public static final java.lang.String WIDTH = "android.media.mediarecorder.width"; + } + public static abstract interface MediaRecorder.OnErrorListener { method public abstract void onError(android.media.MediaRecorder, int, int); } @@ -27705,22 +27734,25 @@ package android.net { method public java.lang.String getName(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); - field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)"; - field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)"; + field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)"; + field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)"; + field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)"; + field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)"; + field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)"; field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR; + field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)"; } 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 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 } @@ -27997,6 +28029,7 @@ package android.net { method public android.net.NetworkRequest.Builder removeCapability(int); method public android.net.NetworkRequest.Builder removeTransportType(int); method public android.net.NetworkRequest.Builder setNetworkSpecifier(java.lang.String); + method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); } public class NetworkScoreManager { @@ -28015,6 +28048,9 @@ package android.net { field public static final java.lang.String EXTRA_PACKAGE_NAME = "packageName"; } + public abstract class NetworkSpecifier { + } + public class ParseException extends java.lang.RuntimeException { field public java.lang.String response; } @@ -28137,10 +28173,6 @@ package android.net { field public static final java.lang.String ATTRIBUTES_KEY_BADGING_CURVE = "android.net.attributes.key.BADGING_CURVE"; field public static final java.lang.String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL"; field public static final java.lang.String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET"; - field public static final deprecated int BADGING_4K = 30; // 0x1e - field public static final deprecated int BADGING_HD = 20; // 0x14 - field public static final deprecated int BADGING_NONE = 0; // 0x0 - field public static final deprecated int BADGING_SD = 10; // 0xa field public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR; field public final android.os.Bundle attributes; field public final boolean meteredHint; @@ -28148,9 +28180,6 @@ package android.net { field public final android.net.RssiCurve rssiCurve; } - public static abstract deprecated class ScoredNetwork.Badging implements java.lang.annotation.Annotation { - } - public class TrafficStats { ctor public TrafficStats(); method public static void clearThreadStatsTag(); @@ -40144,8 +40173,10 @@ package android.service.autofill { method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); - method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback); - method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback); + method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback); + method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback); + method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback); + method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback); field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService"; field public static final java.lang.String SERVICE_META_DATA = "android.autofill"; } @@ -40170,6 +40201,25 @@ package android.service.autofill { method public void onSuccess(android.service.autofill.FillResponse); } + public final class FillContext implements android.os.Parcelable { + method public int describeContents(); + method public int getRequestId(); + method public android.app.assist.AssistStructure getStructure(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR; + } + + public final class FillRequest implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public int getFlags(); + method public int getId(); + method public android.app.assist.AssistStructure getStructure(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR; + field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1 + } + public final class FillResponse implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); @@ -40181,7 +40231,8 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset); method public android.service.autofill.FillResponse build(); 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 setExtras(android.os.Bundle); + 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 setSaveInfo(android.service.autofill.SaveInfo); } @@ -40210,6 +40261,14 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); } + public final class SaveRequest implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public java.util.List<android.service.autofill.FillContext> getFillContexts(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR; + } + } package android.service.carrier { @@ -40985,10 +41044,12 @@ package android.service.wallpaper { method public int getDesiredMinimumHeight(); method public int getDesiredMinimumWidth(); method public android.view.SurfaceHolder getSurfaceHolder(); + method public void invalidateColors(); method public boolean isPreview(); method public boolean isVisible(); method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); + method public android.app.WallpaperColors onComputeWallpaperColors(); method public void onCreate(android.view.SurfaceHolder); method public void onDesiredSizeChanged(int, int); method public void onDestroy(); @@ -48941,7 +49002,6 @@ package android.view { method public android.view.animation.Animation getAnimation(); method public android.os.IBinder getApplicationWindowToken(); method public java.lang.String[] getAutofillHints(); - method public int getAutofillMode(); method public int getAutofillType(); method public android.view.autofill.AutofillValue getAutofillValue(); method public android.graphics.drawable.Drawable getBackground(); @@ -49030,7 +49090,6 @@ package android.view { method public float getPivotX(); method public float getPivotY(); method public android.view.PointerIcon getPointerIcon(); - method public int getResolvedAutofillMode(); method public android.content.res.Resources getResources(); method public final boolean getRevealOnFocusHint(); method public final int getRight(); @@ -49263,7 +49322,6 @@ package android.view { method public void setAlpha(float); method public void setAnimation(android.view.animation.Animation); method public void setAutofillHints(java.lang.String...); - method public void setAutofillMode(int); method public void setBackground(android.graphics.drawable.Drawable); method public void setBackgroundColor(int); method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable); @@ -49419,9 +49477,6 @@ package android.view { field public static final java.lang.String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; field public static final java.lang.String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; field public static final java.lang.String AUTOFILL_HINT_USERNAME = "username"; - field public static final int AUTOFILL_MODE_AUTO = 1; // 0x1 - field public static final int AUTOFILL_MODE_INHERIT = 0; // 0x0 - field public static final int AUTOFILL_MODE_MANUAL = 2; // 0x2 field public static final int AUTOFILL_TYPE_DATE = 4; // 0x4 field public static final int AUTOFILL_TYPE_LIST = 3; // 0x3 field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0 @@ -49989,7 +50044,6 @@ package android.view { method public abstract int getLayoutDirection(); method public abstract android.view.ViewParent getParent(); method public abstract android.view.ViewParent getParentForAccessibility(); - method public default int getResolvedAutofillMode(); method public abstract int getTextAlignment(); method public abstract int getTextDirection(); method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect); @@ -51379,7 +51433,7 @@ package android.view.autofill { field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE"; field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT"; field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS"; - field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1 + field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1 } public static abstract class AutofillManager.AutofillCallback { diff --git a/api/test-current.txt b/api/test-current.txt index f75a872b4c0d..86227a770648 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -211,6 +211,7 @@ package android { ctor public R.attr(); field public static final int __removed1 = 16844099; // 0x1010543 field public static final int __removed2 = 16844104; // 0x1010548 + field public static final int __removed3 = 16844116; // 0x1010554 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -313,7 +314,6 @@ package android { field public static final int autoUrlDetect = 16843404; // 0x101028c field public static final int autoVerify = 16844014; // 0x10104ee field public static final int autofillHints = 16844121; // 0x1010559 - field public static final int autofillMode = 16844116; // 0x1010554 field public static final int background = 16842964; // 0x10100d4 field public static final int backgroundDimAmount = 16842802; // 0x1010032 field public static final int backgroundDimEnabled = 16843295; // 0x101021f @@ -3617,6 +3617,7 @@ package android.app { method public android.net.Uri getReferrer(); method public int getRequestedOrientation(); method public final android.view.SearchEvent getSearchEvent(); + method public long getStartInitiatedTime(); method public int getTaskId(); method public final java.lang.CharSequence getTitle(); method public final int getTitleColor(); @@ -3951,7 +3952,8 @@ package android.app { field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d field public static final int IMPORTANCE_GONE = 1000; // 0x3e8 - field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82 + field public static final int IMPORTANCE_PERCEPTIBLE = 230; // 0xe6 + field public static final deprecated int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; // 0x82 field public static final int IMPORTANCE_SERVICE = 300; // 0x12c field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96 field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8 @@ -6110,6 +6112,17 @@ package android.app { method public void onDetached(); } + public final class WallpaperColors implements android.os.Parcelable { + ctor public WallpaperColors(android.os.Parcel); + ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>); + ctor public WallpaperColors(java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>>, boolean); + method public int describeContents(); + method public java.util.List<android.util.Pair<android.graphics.Color, java.lang.Integer>> getColors(); + method public boolean supportsDarkText(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR; + } + public final class WallpaperInfo implements android.os.Parcelable { ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public int describeContents(); @@ -6132,6 +6145,8 @@ package android.app { } public class WallpaperManager { + method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener); + method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler); method public void clear() throws java.io.IOException; method public void clear(int) throws java.io.IOException; method public void clearWallpaperOffsets(android.os.IBinder); @@ -6146,6 +6161,7 @@ package android.app { method public android.graphics.drawable.Drawable getDrawable(); method public android.graphics.drawable.Drawable getFastDrawable(); method public static android.app.WallpaperManager getInstance(android.content.Context); + method public android.app.WallpaperColors getWallpaperColors(int); method public android.os.ParcelFileDescriptor getWallpaperFile(int); method public int getWallpaperId(int); method public android.app.WallpaperInfo getWallpaperInfo(); @@ -6154,6 +6170,7 @@ package android.app { method public boolean isWallpaperSupported(); method public android.graphics.drawable.Drawable peekDrawable(); method public android.graphics.drawable.Drawable peekFastDrawable(); + method public void removeOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener); method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle); method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException; method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException; @@ -6178,6 +6195,10 @@ package android.app { field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview"; } + public static abstract interface WallpaperManager.OnColorsChangedListener { + method public abstract void onColorsChanged(android.app.WallpaperColors, int); + } + } package android.app.admin { @@ -6823,6 +6844,7 @@ package android.app.job { field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 + field public static final int NETWORK_TYPE_METERED = 4; // 0x4 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 @@ -6897,6 +6919,14 @@ package android.app.job { field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; } + public abstract class JobServiceEngine { + ctor public JobServiceEngine(android.content.Context); + method public final android.os.IBinder getBinder(); + method public final void jobFinished(android.app.job.JobParameters, boolean); + method public abstract boolean onStartJob(android.app.job.JobParameters); + method public abstract boolean onStopJob(android.app.job.JobParameters); + } + public final class JobWorkItem implements android.os.Parcelable { ctor public JobWorkItem(android.content.Intent); ctor public JobWorkItem(android.os.Parcel); @@ -8098,7 +8128,12 @@ package android.bluetooth.le { method public void flushPendingScanResults(android.bluetooth.le.ScanCallback); method public void startScan(android.bluetooth.le.ScanCallback); method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback); + method public int startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.app.PendingIntent); method public void stopScan(android.bluetooth.le.ScanCallback); + method public void stopScan(android.app.PendingIntent); + field public static final java.lang.String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; + field public static final java.lang.String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; + field public static final java.lang.String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT"; } public final class PeriodicAdvertisingParameters implements android.os.Parcelable { @@ -8273,7 +8308,8 @@ package android.companion { method public android.companion.BluetoothLEDeviceFilter build(); method public android.companion.BluetoothLEDeviceFilter.Builder setNamePattern(java.util.regex.Pattern); method public android.companion.BluetoothLEDeviceFilter.Builder setRawDataFilter(byte[], byte[]); - method public android.companion.BluetoothLEDeviceFilter.Builder setRename(java.lang.String, java.lang.String, int, int, boolean); + method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromBytes(java.lang.String, java.lang.String, int, int, boolean); + method public android.companion.BluetoothLEDeviceFilter.Builder setRenameFromName(java.lang.String, java.lang.String, int, int); method public android.companion.BluetoothLEDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter); } @@ -8281,6 +8317,8 @@ package android.companion { method public void associate(android.companion.AssociationRequest, android.companion.CompanionDeviceManager.Callback, android.os.Handler); method public void disassociate(java.lang.String); method public java.util.List<java.lang.String> getAssociations(); + method public boolean hasNotificationAccess(android.content.ComponentName); + method public void requestNotificationAccess(android.content.ComponentName); field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE"; } @@ -9356,7 +9394,6 @@ package android.content { field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED"; field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE"; field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE"; - field public static final deprecated java.lang.String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR"; field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL"; field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON"; field public static final java.lang.String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING"; @@ -12574,6 +12611,7 @@ package android.graphics { field public boolean inJustDecodeBounds; field public boolean inMutable; field public deprecated boolean inPreferQualityOverSpeed; + field public android.graphics.ColorSpace inPreferredColorSpace; field public android.graphics.Bitmap.Config inPreferredConfig; field public boolean inPremultiplied; field public deprecated boolean inPurgeable; @@ -21975,7 +22013,7 @@ package android.media { method public deprecated java.nio.ByteBuffer[] getInputBuffers(); method public final android.media.MediaFormat getInputFormat(); method public android.media.Image getInputImage(int); - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public final java.lang.String getName(); method public java.nio.ByteBuffer getOutputBuffer(int); method public deprecated java.nio.ByteBuffer[] getOutputBuffers(); @@ -22073,6 +22111,19 @@ package android.media { method public void set(int, int); } + public static final class MediaCodec.MetricsConstants { + field public static final java.lang.String CODEC = "android.media.mediacodec.codec"; + field public static final java.lang.String ENCODER = "android.media.mediacodec.encoder"; + field public static final java.lang.String HEIGHT = "android.media.mediacodec.height"; + field public static final java.lang.String MIME_TYPE = "android.media.mediacodec.mime"; + field public static final java.lang.String MODE = "android.media.mediacodec.mode"; + field public static final java.lang.String MODE_AUDIO = "audio"; + field public static final java.lang.String MODE_VIDEO = "video"; + field public static final java.lang.String ROTATION = "android.media.mediacodec.rotation"; + field public static final java.lang.String SECURE = "android.media.mediacodec.secure"; + field public static final java.lang.String WIDTH = "android.media.mediacodec.width"; + } + public static abstract interface MediaCodec.OnFrameRenderedListener { method public abstract void onFrameRendered(android.media.MediaCodec, long, long); } @@ -22528,7 +22579,7 @@ package android.media { method public long getCachedDuration(); method public android.media.MediaExtractor.CasInfo getCasInfo(int); method public android.media.DrmInitData getDrmInitData(); - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public java.util.Map<java.util.UUID, byte[]> getPsshInfo(); method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo); method public int getSampleFlags(); @@ -22563,6 +22614,12 @@ package android.media { method public int getSystemId(); } + public static final class MediaExtractor.MetricsConstants { + field public static final java.lang.String FORMAT = "android.media.mediaextractor.fmt"; + field public static final java.lang.String MIME_TYPE = "android.media.mediaextractor.mime"; + field public static final java.lang.String TRACKS = "android.media.mediaextractor.ntrk"; + } + public final class MediaFormat { ctor public MediaFormat(); method public final boolean containsKey(java.lang.String); @@ -22788,69 +22845,6 @@ package android.media { field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0 } - public final class MediaMetricsSet { - method public double getDouble(java.lang.String, double); - method public int getInt(java.lang.String, int); - method public long getLong(java.lang.String, long); - method public java.lang.String getString(java.lang.String, java.lang.String); - method public boolean isEmpty(); - method public java.util.Set<java.lang.String> keySet(); - method public int size(); - } - - public static final class MediaMetricsSet.MediaCodec { - field public static final java.lang.String KEY_CODEC = "android.media.mediacodec.codec"; - field public static final java.lang.String KEY_ENCODER = "android.media.mediacodec.encoder"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediacodec.height"; - field public static final java.lang.String KEY_MIME = "android.media.mediacodec.mime"; - field public static final java.lang.String KEY_MODE = "android.media.mediacodec.mode"; - field public static final java.lang.String KEY_ROTATION = "android.media.mediacodec.rotation"; - field public static final java.lang.String KEY_SECURE = "android.media.mediacodec.secure"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediacodec.width"; - field public static final java.lang.String MODE_AUDIO = "audio"; - field public static final java.lang.String MODE_VIDEO = "video"; - } - - public static final class MediaMetricsSet.MediaExtractor { - field public static final java.lang.String KEY_FORMAT = "android.media.mediaextractor.fmt"; - field public static final java.lang.String KEY_MIME = "android.media.mediaextractor.mime"; - field public static final java.lang.String KEY_TRACKS = "android.media.mediaextractor.ntrk"; - } - - public static final class MediaMetricsSet.MediaPlayer { - field public static final java.lang.String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; - field public static final java.lang.String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec"; - field public static final java.lang.String KEY_DURATION = "android.media.mediaplayer.durationMs"; - field public static final java.lang.String KEY_ERRORS = "android.media.mediaplayer.err"; - field public static final java.lang.String KEY_ERROR_CODE = "android.media.mediaplayer.errcode"; - field public static final java.lang.String KEY_FRAMES = "android.media.mediaplayer.frames"; - field public static final java.lang.String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediaplayer.height"; - field public static final java.lang.String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime"; - field public static final java.lang.String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime"; - field public static final java.lang.String KEY_PLAYING = "android.media.mediaplayer.playingMs"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediaplayer.width"; - } - - public static final class MediaMetricsSet.MediaRecorder { - field public static final java.lang.String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; - field public static final java.lang.String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; - field public static final java.lang.String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; - field public static final java.lang.String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; - field public static final java.lang.String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; - field public static final java.lang.String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; - field public static final java.lang.String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate"; - field public static final java.lang.String KEY_HEIGHT = "android.media.mediarecorder.height"; - field public static final java.lang.String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; - field public static final java.lang.String KEY_ROTATION = "android.media.mediarecorder.rotation"; - field public static final java.lang.String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; - field public static final java.lang.String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; - field public static final java.lang.String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; - field public static final java.lang.String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; - field public static final java.lang.String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; - field public static final java.lang.String KEY_WIDTH = "android.media.mediarecorder.width"; - } - public final class MediaMuxer { ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException; ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException; @@ -22889,7 +22883,7 @@ package android.media { 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.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); @@ -22984,6 +22978,21 @@ package android.media { method public java.util.UUID[] getSupportedSchemes(); } + public static final class MediaPlayer.MetricsConstants { + field public static final java.lang.String CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; + field public static final java.lang.String CODEC_VIDEO = "android.media.mediaplayer.video.codec"; + field public static final java.lang.String DURATION = "android.media.mediaplayer.durationMs"; + field public static final java.lang.String ERRORS = "android.media.mediaplayer.err"; + field public static final java.lang.String ERROR_CODE = "android.media.mediaplayer.errcode"; + field public static final java.lang.String FRAMES = "android.media.mediaplayer.frames"; + field public static final java.lang.String FRAMES_DROPPED = "android.media.mediaplayer.dropped"; + field public static final java.lang.String HEIGHT = "android.media.mediaplayer.height"; + field public static final java.lang.String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime"; + field public static final java.lang.String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime"; + field public static final java.lang.String PLAYING = "android.media.mediaplayer.playingMs"; + field public static final java.lang.String WIDTH = "android.media.mediaplayer.width"; + } + public static final class MediaPlayer.NoDrmSchemeException extends android.media.MediaDrmException { ctor public MediaPlayer.NoDrmSchemeException(java.lang.String); } @@ -23058,7 +23067,7 @@ package android.media { ctor public MediaRecorder(); method public static final int getAudioSourceMax(); method public int getMaxAmplitude() throws java.lang.IllegalStateException; - method public android.media.MediaMetricsSet getMetrics(); + method public android.os.PersistableBundle getMetrics(); method public android.view.Surface getSurface(); method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; @@ -23126,6 +23135,25 @@ package android.media { field public static final int VOICE_UPLINK = 2; // 0x2 } + public static final class MediaRecorder.MetricsConstants { + field public static final java.lang.String AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; + field public static final java.lang.String AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; + field public static final java.lang.String AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; + field public static final java.lang.String AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; + field public static final java.lang.String CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; + field public static final java.lang.String CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; + field public static final java.lang.String FRAMERATE = "android.media.mediarecorder.frame-rate"; + field public static final java.lang.String HEIGHT = "android.media.mediarecorder.height"; + field public static final java.lang.String MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; + field public static final java.lang.String ROTATION = "android.media.mediarecorder.rotation"; + field public static final java.lang.String VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; + field public static final java.lang.String VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; + field public static final java.lang.String VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; + field public static final java.lang.String VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; + field public static final java.lang.String VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; + field public static final java.lang.String WIDTH = "android.media.mediarecorder.width"; + } + public static abstract interface MediaRecorder.OnErrorListener { method public abstract void onError(android.media.MediaRecorder, int, int); } @@ -25627,22 +25655,25 @@ package android.net { method public java.lang.String getName(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); - field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)"; - field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)"; - field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)"; + field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)"; + field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)"; + field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)"; + field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)"; + field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)"; field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR; + field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)"; } 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 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 } @@ -25882,6 +25913,10 @@ package android.net { method public android.net.NetworkRequest.Builder removeCapability(int); method public android.net.NetworkRequest.Builder removeTransportType(int); method public android.net.NetworkRequest.Builder setNetworkSpecifier(java.lang.String); + method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); + } + + public abstract class NetworkSpecifier { } public class ParseException extends java.lang.RuntimeException { @@ -37181,8 +37216,10 @@ package android.service.autofill { method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); - method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback); - method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback); + method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback); + method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback); + method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback); + method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback); field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService"; field public static final java.lang.String SERVICE_META_DATA = "android.autofill"; } @@ -37207,6 +37244,25 @@ package android.service.autofill { method public void onSuccess(android.service.autofill.FillResponse); } + public final class FillContext implements android.os.Parcelable { + method public int describeContents(); + method public int getRequestId(); + method public android.app.assist.AssistStructure getStructure(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR; + } + + public final class FillRequest implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public int getFlags(); + method public int getId(); + method public android.app.assist.AssistStructure getStructure(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR; + field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1 + } + public final class FillResponse implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); @@ -37218,7 +37274,8 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset); method public android.service.autofill.FillResponse build(); 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 setExtras(android.os.Bundle); + 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 setSaveInfo(android.service.autofill.SaveInfo); } @@ -37247,6 +37304,14 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); } + public final class SaveRequest implements android.os.Parcelable { + method public int describeContents(); + method public android.os.Bundle getClientState(); + method public java.util.List<android.service.autofill.FillContext> getFillContexts(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR; + } + } package android.service.carrier { @@ -37921,10 +37986,12 @@ package android.service.wallpaper { method public int getDesiredMinimumHeight(); method public int getDesiredMinimumWidth(); method public android.view.SurfaceHolder getSurfaceHolder(); + method public void invalidateColors(); method public boolean isPreview(); method public boolean isVisible(); method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); + method public android.app.WallpaperColors onComputeWallpaperColors(); method public void onCreate(android.view.SurfaceHolder); method public void onDesiredSizeChanged(int, int); method public void onDestroy(); @@ -45727,7 +45794,6 @@ package android.view { method public android.view.animation.Animation getAnimation(); method public android.os.IBinder getApplicationWindowToken(); method public java.lang.String[] getAutofillHints(); - method public int getAutofillMode(); method public int getAutofillType(); method public android.view.autofill.AutofillValue getAutofillValue(); method public android.graphics.drawable.Drawable getBackground(); @@ -45816,7 +45882,6 @@ package android.view { method public float getPivotX(); method public float getPivotY(); method public android.view.PointerIcon getPointerIcon(); - method public int getResolvedAutofillMode(); method public android.content.res.Resources getResources(); method public final boolean getRevealOnFocusHint(); method public final int getRight(); @@ -46052,7 +46117,6 @@ package android.view { method public void setAlpha(float); method public void setAnimation(android.view.animation.Animation); method public void setAutofillHints(java.lang.String...); - method public void setAutofillMode(int); method public void setAutofilled(boolean); method public void setBackground(android.graphics.drawable.Drawable); method public void setBackgroundColor(int); @@ -46209,9 +46273,6 @@ package android.view { field public static final java.lang.String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; field public static final java.lang.String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; field public static final java.lang.String AUTOFILL_HINT_USERNAME = "username"; - field public static final int AUTOFILL_MODE_AUTO = 1; // 0x1 - field public static final int AUTOFILL_MODE_INHERIT = 0; // 0x0 - field public static final int AUTOFILL_MODE_MANUAL = 2; // 0x2 field public static final int AUTOFILL_TYPE_DATE = 4; // 0x4 field public static final int AUTOFILL_TYPE_LIST = 3; // 0x3 field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0 @@ -46783,7 +46844,6 @@ package android.view { method public abstract int getLayoutDirection(); method public abstract android.view.ViewParent getParent(); method public abstract android.view.ViewParent getParentForAccessibility(); - method public default int getResolvedAutofillMode(); method public abstract int getTextAlignment(); method public abstract int getTextDirection(); method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect); @@ -48174,7 +48234,7 @@ package android.view.autofill { field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE"; field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT"; field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS"; - field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1 + field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1 } public static abstract class AutofillManager.AutofillCallback { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 950991b75546..b36a1600bae5 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -18,6 +18,7 @@ package android.app; import android.metrics.LogMaker; import android.graphics.Rect; +import android.os.SystemClock; import android.view.ViewRootImpl.ActivityConfigCallback; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; @@ -7433,6 +7434,25 @@ public class Activity extends ContextThemeWrapper } } + /** + * Return the timestamp at which this activity start was last initiated by the system in the + * {@link SystemClock#uptimeMillis()} time base. + * + * This can be used to understand how much time is taken for an activity to be started and + * displayed to the user. + * + * @return timestamp at which this activity start was initiated by the system + * or {@code 0} if for any reason the timestamp could not be retrieved. + */ + public long getStartInitiatedTime() { + try { + return ActivityManager.getService().getActivityStartInitiatedTime(mToken); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call getActivityStartTime", e); + return 0; + } + } + class HostCallbacks extends FragmentHostCallback<Activity> { public HostCallbacks() { super(Activity.this /*activity*/); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 88598313724e..66167a3c986a 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -30,6 +30,8 @@ import android.graphics.GraphicBuffer; import android.graphics.Matrix; import android.graphics.Point; import android.os.BatteryStats; +import android.os.Build; +import android.os.Build.VERSION_CODES; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -138,14 +140,17 @@ public class ActivityManager { static final class UidObserver extends IUidObserver.Stub { final OnUidImportanceListener mListener; + final Context mContext; - UidObserver(OnUidImportanceListener listener) { + UidObserver(OnUidImportanceListener listener, Context clientContext) { mListener = listener; + mContext = clientContext; } @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) { - mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportance(procState)); + mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportanceForClient( + procState, mContext)); } @Override @@ -3102,10 +3107,32 @@ public class ActivityManager { public static final int IMPORTANCE_VISIBLE = 200; /** + * Constant for {@link #importance}: {@link #IMPORTANCE_PERCEPTIBLE} had this wrong value + * before {@link Build.VERSION_CODES#O}. Since the {@link Build.VERSION_CODES#O} SDK, + * the value of {@link #IMPORTANCE_PERCEPTIBLE} has been fixed. + * + * @deprecated Use {@link #IMPORTANCE_PERCEPTIBLE} instead. + */ + @Deprecated + public static final int IMPORTANCE_PERCEPTIBLE_DEPRECATED = 130; + + /** * Constant for {@link #importance}: This process is not something the user - * is directly aware of, but is otherwise perceptable to them to some degree. + * is directly aware of, but is otherwise perceptible to them to some degree. + */ + public static final int IMPORTANCE_PERCEPTIBLE = 230; + + /** + * Constant for {@link #importance}: {@link #IMPORTANCE_CANT_SAVE_STATE} had + * this wrong value + * before {@link Build.VERSION_CODES#O}. Since the {@link Build.VERSION_CODES#O} SDK, + * the value of {@link #IMPORTANCE_CANT_SAVE_STATE} has been fixed. + * + * @deprecated Use {@link #IMPORTANCE_CANT_SAVE_STATE} instead. + * @hide */ - public static final int IMPORTANCE_PERCEPTIBLE = 130; + @Deprecated + public static final int IMPORTANCE_CANT_SAVE_STATE_DEPRECATED = 170; /** * Constant for {@link #importance}: This process is running an @@ -3113,7 +3140,7 @@ public class ActivityManager { * while in the background. * @hide */ - public static final int IMPORTANCE_CANT_SAVE_STATE = 170; + public static final int IMPORTANCE_CANT_SAVE_STATE= 270; /** * Constant for {@link #importance}: This process is contains services @@ -3149,7 +3176,11 @@ public class ActivityManager { */ public static final int IMPORTANCE_GONE = 1000; - /** @hide */ + /** + * Convert a proc state to the correspondent IMPORTANCE_* constant. If the return value + * will be passed to a client, use {@link #procStateToImportanceForClient}. + * @hide + */ public static int procStateToImportance(int procState) { if (procState == PROCESS_STATE_NONEXISTENT) { return IMPORTANCE_GONE; @@ -3172,6 +3203,28 @@ public class ActivityManager { } } + /** + * Convert a proc state to the correspondent IMPORTANCE_* constant for a client represented + * by a given {@link Context}, with converting {@link #IMPORTANCE_PERCEPTIBLE} + * and {@link #IMPORTANCE_CANT_SAVE_STATE} to the corresponding "wrong" value if the + * client's target SDK < {@link VERSION_CODES#O}. + * @hide + */ + public static int procStateToImportanceForClient(int procState, Context clientContext) { + final int importance = procStateToImportance(procState); + + // For pre O apps, convert to the old, wrong values. + if (clientContext.getApplicationInfo().targetSdkVersion < VERSION_CODES.O) { + switch (importance) { + case IMPORTANCE_PERCEPTIBLE: + return IMPORTANCE_PERCEPTIBLE_DEPRECATED; + case IMPORTANCE_CANT_SAVE_STATE: + return IMPORTANCE_CANT_SAVE_STATE_DEPRECATED; + } + } + return importance; + } + /** @hide */ public static int importanceToProcState(int importance) { if (importance == IMPORTANCE_GONE) { @@ -3401,7 +3454,7 @@ public class ActivityManager { try { int procState = getService().getPackageProcessState(packageName, mContext.getOpPackageName()); - return RunningAppProcessInfo.procStateToImportance(procState); + return RunningAppProcessInfo.procStateToImportanceForClient(procState, mContext); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3421,7 +3474,7 @@ public class ActivityManager { try { int procState = getService().getUidProcessState(uid, mContext.getOpPackageName()); - return RunningAppProcessInfo.procStateToImportance(procState); + return RunningAppProcessInfo.procStateToImportanceForClient(procState, mContext); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3471,7 +3524,7 @@ public class ActivityManager { throw new IllegalArgumentException("Listener already registered: " + listener); } // TODO: implement the cut point in the system process to avoid IPCs. - UidObserver observer = new UidObserver(listener); + UidObserver observer = new UidObserver(listener, mContext); try { getService().registerUidObserver(observer, UID_OBSERVER_PROCSTATE | UID_OBSERVER_GONE, diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index fc827a946a44..4210d2e7d3ec 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -632,6 +632,8 @@ interface IActivityManager { */ void backgroundWhitelistUid(int uid); + long getActivityStartInitiatedTime(IBinder token); + // WARNING: when these transactions are updated, check if they are any callers on the native // side. If so, make sure they are using the correct transaction ids and arguments. // If a transaction which will also be used on the native side is being inserted, add it diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java new file mode 100644 index 000000000000..5ed66cac5f8f --- /dev/null +++ b/core/java/android/app/WallpaperColors.java @@ -0,0 +1,97 @@ +/* + * 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.app; + +import android.graphics.Color; +import android.os.Parcel; +import android.os.Parcelable; + +import android.util.Pair; + +import java.util.List; + +/** + * A class containing information about the colors of a wallpaper. + */ +public final class WallpaperColors implements Parcelable { + + public WallpaperColors(Parcel parcel) { + } + + /** + * Wallpaper color details containing a list of colors and their weights, + * as if it were an histogram. + * This list can be extracted from a bitmap by the Palette API. + * + * Dark text support will be calculated internally based on the histogram. + * + * @param colors list of pairs where each pair contains a color + * and number of occurrences/influence. + */ + public WallpaperColors(List<Pair<Color, Integer>> colors) { + } + + /** + * Wallpaper color details containing a list of colors and their weights, + * as if it were an histogram. + * Explicit dark text support. + * + * @param colors list of pairs where each pair contains a color + * and number of occurrences/influence. + * @param supportsDarkText can have dark text on top or not + */ + public WallpaperColors(List<Pair<Color, Integer>> colors, boolean supportsDarkText) { + } + + public static final Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() { + @Override + public WallpaperColors createFromParcel(Parcel in) { + return new WallpaperColors(in); + } + + @Override + public WallpaperColors[] newArray(int size) { + return new WallpaperColors[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + } + + /** + * List of colors with their occurrences. The bigger the int, the more relevant the color. + * @return list of colors paired with their weights. + */ + public List<Pair<Color, Integer>> getColors() { + return null; + } + + /** + * Whether or not dark text is legible on top of this wallpaper. + * + * @return true if dark text is supported + */ + public boolean supportsDarkText() { + return false; + } +} diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index aa0eaaebf975..0676bca0e796 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -17,6 +17,8 @@ package android.app; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RawRes; import android.annotation.SystemApi; import android.content.ComponentName; @@ -741,6 +743,43 @@ public class WallpaperManager { return getWallpaperFile(which, mContext.getUserId()); } + + /** + * Registers a listener to get notified when the wallpaper colors change. + * Callback might be called from an arbitrary background thread. + * + * @param listener A listener to register + */ + public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) { + } + + /** + * Registers a listener to get notified when the wallpaper colors change + * @param listener A listener to register + * @param handler Where to call it from. Might be called from a background thread + * if null. + */ + public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener, + @Nullable Handler handler) { + } + + /** + * Stop listening to color updates. + * @param callback A callback to unsubscribe + */ + public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback) { + } + + /** + * Get the primary colors of a wallpaper + * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or + * {@link #FLAG_LOCK} + * @return a list of colors ordered by priority + */ + public @Nullable WallpaperColors getWallpaperColors(int which) { + return null; + } + /** * Version of {@link #getWallpaperFile(int)} that can access the wallpaper data * for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL @@ -1732,4 +1771,19 @@ public class WallpaperManager { mLatch.countDown(); } } + + /** + * Interface definition for a callback to be invoked when colors change on a wallpaper. + */ + public interface OnColorsChangedListener { + /** + * Called when colors change. + * A {@link android.app.WallpaperColors} object containing a simplified + * color histogram will be given. + * + * @param colors Wallpaper color info + * @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM} + */ + void onColorsChanged(WallpaperColors colors, int which); + } } diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index 412e4459ecdd..23baa17d947f 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -51,6 +51,8 @@ public class JobInfo implements Parcelable { public static final int NETWORK_TYPE_UNMETERED = 2; /** This job requires network connectivity that is not roaming. */ public static final int NETWORK_TYPE_NOT_ROAMING = 3; + /** This job requires metered connectivity such as most cellular data networks. */ + public static final int NETWORK_TYPE_METERED = 4; /** * Amount of backoff a job has initially by default, in milliseconds. @@ -347,10 +349,13 @@ public class JobInfo implements Parcelable { } /** - * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY}, + * The kind of connectivity requirements that the job has. + * + * @return One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY}, * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, - * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}, or - * {@link android.app.job.JobInfo#NETWORK_TYPE_NOT_ROAMING}. + * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}, + * {@link android.app.job.JobInfo#NETWORK_TYPE_METERED}, or + * {@link android.app.job.JobInfo#NETWORK_TYPE_NOT_ROAMING}, */ public int getNetworkType() { return networkType; diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java index f4019ce446f7..9096b47b8d4d 100644 --- a/core/java/android/app/job/JobService.java +++ b/core/java/android/app/job/JobService.java @@ -60,161 +60,24 @@ public abstract class JobService extends Service { public static final String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE"; - /** - * Identifier for a message that will result in a call to - * {@link #onStartJob(android.app.job.JobParameters)}. - */ - private static final int MSG_EXECUTE_JOB = 0; - /** - * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}. - */ - private static final int MSG_STOP_JOB = 1; - /** - * Message that the client has completed execution of this job. - */ - private static final int MSG_JOB_FINISHED = 2; - - /** Lock object for {@link #mHandler}. */ - private final Object mHandlerLock = new Object(); - - /** - * Handler we post jobs to. Responsible for calling into the client logic, and handling the - * callback to the system. - */ - @GuardedBy("mHandlerLock") - JobHandler mHandler; - - static final class JobInterface extends IJobService.Stub { - final WeakReference<JobService> mService; - - JobInterface(JobService service) { - mService = new WeakReference<>(service); - } - - @Override - public void startJob(JobParameters jobParams) throws RemoteException { - JobService service = mService.get(); - if (service != null) { - service.ensureHandler(); - Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams); - m.sendToTarget(); - } - } - - @Override - public void stopJob(JobParameters jobParams) throws RemoteException { - JobService service = mService.get(); - if (service != null) { - service.ensureHandler(); - Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams); - m.sendToTarget(); - } - - } - } - - IJobService mBinder; + private JobServiceEngine mEngine; /** @hide */ - void ensureHandler() { - synchronized (mHandlerLock) { - if (mHandler == null) { - mHandler = new JobHandler(getMainLooper()); - } - } - } - - /** - * Runs on application's main thread - callbacks are meant to offboard work to some other - * (app-specified) mechanism. - * @hide - */ - class JobHandler extends Handler { - JobHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - final JobParameters params = (JobParameters) msg.obj; - switch (msg.what) { - case MSG_EXECUTE_JOB: - try { - boolean workOngoing = JobService.this.onStartJob(params); - ackStartMessage(params, workOngoing); - } catch (Exception e) { - Log.e(TAG, "Error while executing job: " + params.getJobId()); - throw new RuntimeException(e); - } - break; - case MSG_STOP_JOB: - try { - boolean ret = JobService.this.onStopJob(params); - ackStopMessage(params, ret); - } catch (Exception e) { - Log.e(TAG, "Application unable to handle onStopJob.", e); - throw new RuntimeException(e); - } - break; - case MSG_JOB_FINISHED: - final boolean needsReschedule = (msg.arg2 == 1); - IJobCallback callback = params.getCallback(); - if (callback != null) { - try { - callback.jobFinished(params.getJobId(), needsReschedule); - } catch (RemoteException e) { - Log.e(TAG, "Error reporting job finish to system: binder has gone" + - "away."); - } - } else { - Log.e(TAG, "finishJob() called for a nonexistent job id."); - } - break; - default: - Log.e(TAG, "Unrecognised message received."); - break; - } - } - - private void ackStartMessage(JobParameters params, boolean workOngoing) { - final IJobCallback callback = params.getCallback(); - final int jobId = params.getJobId(); - if (callback != null) { - try { - callback.acknowledgeStartMessage(jobId, workOngoing); - } catch(RemoteException e) { - Log.e(TAG, "System unreachable for starting job."); - } - } else { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Attempting to ack a job that has already been processed."); + public final IBinder onBind(Intent intent) { + if (mEngine == null) { + mEngine = new JobServiceEngine(this) { + @Override + public boolean onStartJob(JobParameters params) { + return JobService.this.onStartJob(params); } - } - } - private void ackStopMessage(JobParameters params, boolean reschedule) { - final IJobCallback callback = params.getCallback(); - final int jobId = params.getJobId(); - if (callback != null) { - try { - callback.acknowledgeStopMessage(jobId, reschedule); - } catch(RemoteException e) { - Log.e(TAG, "System unreachable for stopping job."); + @Override + public boolean onStopJob(JobParameters params) { + return JobService.this.onStopJob(params); } - } else { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Attempting to ack a job that has already been processed."); - } - } - } - } - - /** @hide */ - public final IBinder onBind(Intent intent) { - if (mBinder == null) { - mBinder = new JobInterface(this); + }; } - return mBinder.asBinder(); + return mEngine.getBinder(); } /** @@ -269,9 +132,6 @@ public abstract class JobService extends Service { * criteria specified at schedule-time. False otherwise. */ public final void jobFinished(JobParameters params, boolean needsReschedule) { - ensureHandler(); - Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params); - m.arg2 = needsReschedule ? 1 : 0; - m.sendToTarget(); + mEngine.jobFinished(params, needsReschedule); } }
\ No newline at end of file diff --git a/core/java/android/app/job/JobServiceEngine.java b/core/java/android/app/job/JobServiceEngine.java new file mode 100644 index 000000000000..879212ea1fb3 --- /dev/null +++ b/core/java/android/app/job/JobServiceEngine.java @@ -0,0 +1,223 @@ +/* + * 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 + */ + +package android.app.job; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; + +import java.lang.ref.WeakReference; + +/** + * Helper for implementing a {@link android.app.Service} that interacts with + * {@link JobScheduler}. + */ +public abstract class JobServiceEngine { + private static final String TAG = "JobServiceEngine"; + + /** + * Identifier for a message that will result in a call to + * {@link #onStartJob(android.app.job.JobParameters)}. + */ + private static final int MSG_EXECUTE_JOB = 0; + /** + * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}. + */ + private static final int MSG_STOP_JOB = 1; + /** + * Message that the client has completed execution of this job. + */ + private static final int MSG_JOB_FINISHED = 2; + + /** + * Context we are running in. + */ + private final Context mContext; + + private final IJobService mBinder; + + /** Lock object for {@link #mHandler}. */ + private final Object mHandlerLock = new Object(); + + /** + * Handler we post jobs to. Responsible for calling into the client logic, and handling the + * callback to the system. + */ + @GuardedBy("mHandlerLock") + JobHandler mHandler; + + static final class JobInterface extends IJobService.Stub { + final WeakReference<JobServiceEngine> mService; + + JobInterface(JobServiceEngine service) { + mService = new WeakReference<>(service); + } + + @Override + public void startJob(JobParameters jobParams) throws RemoteException { + JobServiceEngine service = mService.get(); + if (service != null) { + Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams); + m.sendToTarget(); + } + } + + @Override + public void stopJob(JobParameters jobParams) throws RemoteException { + JobServiceEngine service = mService.get(); + if (service != null) { + Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams); + m.sendToTarget(); + } + } + } + + /** + * Runs on application's main thread - callbacks are meant to offboard work to some other + * (app-specified) mechanism. + * @hide + */ + class JobHandler extends Handler { + JobHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + final JobParameters params = (JobParameters) msg.obj; + switch (msg.what) { + case MSG_EXECUTE_JOB: + try { + boolean workOngoing = JobServiceEngine.this.onStartJob(params); + ackStartMessage(params, workOngoing); + } catch (Exception e) { + Log.e(TAG, "Error while executing job: " + params.getJobId()); + throw new RuntimeException(e); + } + break; + case MSG_STOP_JOB: + try { + boolean ret = JobServiceEngine.this.onStopJob(params); + ackStopMessage(params, ret); + } catch (Exception e) { + Log.e(TAG, "Application unable to handle onStopJob.", e); + throw new RuntimeException(e); + } + break; + case MSG_JOB_FINISHED: + final boolean needsReschedule = (msg.arg2 == 1); + IJobCallback callback = params.getCallback(); + if (callback != null) { + try { + callback.jobFinished(params.getJobId(), needsReschedule); + } catch (RemoteException e) { + Log.e(TAG, "Error reporting job finish to system: binder has gone" + + "away."); + } + } else { + Log.e(TAG, "finishJob() called for a nonexistent job id."); + } + break; + default: + Log.e(TAG, "Unrecognised message received."); + break; + } + } + + private void ackStartMessage(JobParameters params, boolean workOngoing) { + final IJobCallback callback = params.getCallback(); + final int jobId = params.getJobId(); + if (callback != null) { + try { + callback.acknowledgeStartMessage(jobId, workOngoing); + } catch(RemoteException e) { + Log.e(TAG, "System unreachable for starting job."); + } + } else { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Attempting to ack a job that has already been processed."); + } + } + } + + private void ackStopMessage(JobParameters params, boolean reschedule) { + final IJobCallback callback = params.getCallback(); + final int jobId = params.getJobId(); + if (callback != null) { + try { + callback.acknowledgeStopMessage(jobId, reschedule); + } catch(RemoteException e) { + Log.e(TAG, "System unreachable for stopping job."); + } + } else { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Attempting to ack a job that has already been processed."); + } + } + } + } + + /** + * Create a new engine, ready for use. + * + * @param context The {@link Service} that is creating this engine. + */ + public JobServiceEngine(Context context) { + mContext = context; + mBinder = new JobInterface(this); + mHandler = new JobHandler(mContext.getMainLooper()); + } + + /** + * Retrieve the engine's IPC interface that should be returned by + * {@link Service#onBind(Intent)}. + */ + public final IBinder getBinder() { + return mBinder.asBinder(); + } + + /** + * Engine's report that a job has started. See + * {@link JobService#onStartJob(JobParameters) JobService.onStartJob} for more information. + */ + public abstract boolean onStartJob(JobParameters params); + + /** + * Engine's report that a job has stopped. See + * {@link JobService#onStopJob(JobParameters) JobService.onStopJob} for more information. + */ + public abstract boolean onStopJob(JobParameters params); + + /** + * Call in to engine to report that a job has finished executing. See + * {@link JobService#jobFinished(JobParameters, boolean)} JobService.jobFinished} for more + * information. + */ + public final void jobFinished(JobParameters params, boolean needsReschedule) { + Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params); + m.arg2 = needsReschedule ? 1 : 0; + m.sendToTarget(); + } +}
\ No newline at end of file diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index 334e88b69fde..582709c3ba47 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -16,6 +16,7 @@ package android.bluetooth; +import android.app.PendingIntent; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGattService; import android.bluetooth.le.AdvertiseSettings; @@ -47,6 +48,9 @@ interface IBluetoothGatt { void unregisterScanner(in int scannerId); void startScan(in int scannerId, in ScanSettings settings, in List<ScanFilter> filters, in WorkSource workSource, in List scanStorages, in String callingPackage); + void startScanForIntent(in PendingIntent intent, in ScanSettings settings, in List<ScanFilter> filters, + in String callingPackage); + void stopScanForIntent(in PendingIntent intent, in String callingPackage); void stopScan(in int scannerId); void flushPendingBatchResults(in int scannerId); diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index b63c614711ea..b65a7ad0c017 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -17,17 +17,18 @@ package android.bluetooth.le; import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.ActivityThread; +import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothGatt; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothManager; -import android.bluetooth.le.IScannerCallback; import android.os.Handler; import android.os.Looper; -import android.os.ParcelUuid; import android.os.RemoteException; import android.os.WorkSource; import android.util.Log; @@ -36,7 +37,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; /** * This class provides methods to perform scan related operations for Bluetooth LE devices. An @@ -57,6 +57,27 @@ public final class BluetoothLeScanner { private static final boolean DBG = true; private static final boolean VDBG = false; + /** + * Extra containing a list of ScanResults. It can have one or more results if there was no + * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this + * extra will not be available. + */ + public static final String EXTRA_LIST_SCAN_RESULT + = "android.bluetooth.le.extra.LIST_SCAN_RESULT"; + + /** + * Optional extra indicating the error code, if any. The error code will be one of the + * SCAN_FAILED_* codes in {@link ScanCallback}. + */ + public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; + + /** + * Optional extra indicating the callback type, which will be one of + * ScanSettings.CALLBACK_TYPE_*. + * @see ScanCallback#onScanResult(int, ScanResult) + */ + public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; + private final IBluetoothManager mBluetoothManager; private final Handler mHandler; private BluetoothAdapter mBluetoothAdapter; @@ -110,7 +131,27 @@ public final class BluetoothLeScanner { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public void startScan(List<ScanFilter> filters, ScanSettings settings, final ScanCallback callback) { - startScan(filters, settings, null, callback, null); + startScan(filters, settings, null, callback, /*callbackIntent=*/ null, null); + } + + /** + * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via + * the PendingIntent. Use this method of scanning if your process is not always running and it + * should be started when scan results are available. + * + * @param filters Optional list of ScanFilters for finding exact BLE devices. + * @param settings Optional settings for the scan. + * @param callbackIntent The PendingIntent to deliver the result to. + * @return Returns 0 for success or an error code from {@link ScanCallback} if the scan request + * could not be sent. + * @see #stopScan(PendingIntent) + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings, + @NonNull PendingIntent callbackIntent) { + return startScan(filters, + settings != null ? settings : new ScanSettings.Builder().build(), + null, null, callbackIntent, null); } /** @@ -145,23 +186,23 @@ public final class BluetoothLeScanner { Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS }) public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings, final WorkSource workSource, final ScanCallback callback) { - startScan(filters, settings, workSource, callback, null); + startScan(filters, settings, workSource, callback, null, null); } - private void startScan(List<ScanFilter> filters, ScanSettings settings, + private int startScan(List<ScanFilter> filters, ScanSettings settings, final WorkSource workSource, final ScanCallback callback, + final PendingIntent callbackIntent, List<List<ResultStorageDescriptor>> resultStorages) { BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); - if (callback == null) { + if (callback == null && callbackIntent == null) { throw new IllegalArgumentException("callback is null"); } if (settings == null) { throw new IllegalArgumentException("settings is null"); } synchronized (mLeScanClients) { - if (mLeScanClients.containsKey(callback)) { + if (callback != null && mLeScanClients.containsKey(callback)) { postCallbackError(callback, ScanCallback.SCAN_FAILED_ALREADY_STARTED); - return; } IBluetoothGatt gatt; try { @@ -170,28 +211,34 @@ public final class BluetoothLeScanner { gatt = null; } if (gatt == null) { - postCallbackError(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); - return; + return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); } if (!isSettingsConfigAllowedForScan(settings)) { - postCallbackError(callback, - ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); - return; + return postCallbackErrorOrReturn(callback, + ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); } if (!isHardwareResourcesAvailableForScan(settings)) { - postCallbackError(callback, - ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES); - return; + return postCallbackErrorOrReturn(callback, + ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES); } if (!isSettingsAndFilterComboAllowed(settings, filters)) { - postCallbackError(callback, + return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); - return; } - BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters, - settings, workSource, callback, resultStorages); - wrapper.startRegisteration(); + if (callback != null) { + BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters, + settings, workSource, callback, resultStorages); + wrapper.startRegistration(); + } else { + try { + gatt.startScanForIntent(callbackIntent, settings, filters, + ActivityThread.currentOpPackageName()); + } catch (RemoteException e) { + return ScanCallback.SCAN_FAILED_INTERNAL_ERROR; + } + } } + return ScanCallback.NO_ERROR; } /** @@ -215,6 +262,25 @@ public final class BluetoothLeScanner { } /** + * Stops an ongoing Bluetooth LE scan started using a PendingIntent. + * <p> + * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * + * @param callbackIntent The PendingIntent that was used to start the scan. + * @see #startScan(List, ScanSettings, PendingIntent) + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public void stopScan(PendingIntent callbackIntent) { + BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); + IBluetoothGatt gatt; + try { + gatt = mBluetoothManager.getBluetoothGatt(); + gatt.stopScanForIntent(callbackIntent, ActivityThread.currentOpPackageName()); + } catch (RemoteException e) { + } + } + + /** * Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth * LE scan results batched on bluetooth controller. Returns immediately, batch scan results data * will be delivered through the {@code callback}. @@ -252,7 +318,7 @@ public final class BluetoothLeScanner { scanFilters.add(filter.getFilter()); scanStorages.add(filter.getStorageDescriptors()); } - startScan(scanFilters, settings, null, callback, scanStorages); + startScan(scanFilters, settings, null, callback, null, scanStorages); } /** @@ -295,7 +361,7 @@ public final class BluetoothLeScanner { mResultStorages = resultStorages; } - public void startRegisteration() { + public void startRegistration() { synchronized (this) { // Scan stopped. if (mScannerId == -1) return; @@ -399,7 +465,6 @@ public final class BluetoothLeScanner { mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult); } }); - } @Override @@ -453,6 +518,15 @@ public final class BluetoothLeScanner { } } + private int postCallbackErrorOrReturn(final ScanCallback callback, final int errorCode) { + if (callback == null) { + return errorCode; + } else { + postCallbackError(callback, errorCode); + return ScanCallback.NO_ERROR; + } + } + private void postCallbackError(final ScanCallback callback, final int errorCode) { mHandler.post(new Runnable() { @Override diff --git a/core/java/android/bluetooth/le/ScanCallback.java b/core/java/android/bluetooth/le/ScanCallback.java index 61b2e787c86c..aff2e9095024 100644 --- a/core/java/android/bluetooth/le/ScanCallback.java +++ b/core/java/android/bluetooth/le/ScanCallback.java @@ -50,6 +50,8 @@ public abstract class ScanCallback { */ public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5; + static final int NO_ERROR = 0; + /** * Callback when a BLE advertisement has been found. * diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java index 8a316f19af8e..3665d1b85bcb 100644 --- a/core/java/android/companion/BluetoothDeviceFilterUtils.java +++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java @@ -37,7 +37,7 @@ public class BluetoothDeviceFilterUtils { private BluetoothDeviceFilterUtils() {} private static final boolean DEBUG = false; - private static final String LOG_TAG = "BluetoothDeviceFilterUtil"; + private static final String LOG_TAG = "BluetoothDeviceFilterUtils"; @Nullable static String patternToString(@Nullable Pattern p) { @@ -50,8 +50,10 @@ public class BluetoothDeviceFilterUtils { } static boolean matches(ScanFilter filter, BluetoothDevice device) { - return matchesAddress(filter.getDeviceAddress(), device) + boolean result = matchesAddress(filter.getDeviceAddress(), device) && matchesServiceUuid(filter.getServiceUuid(), filter.getServiceUuidMask(), device); + if (DEBUG) debugLogMatchResult(result, device, filter); + return result; } static boolean matchesAddress(String deviceAddress, BluetoothDevice device) { diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java index 0444775871b9..76051d722368 100644 --- a/core/java/android/companion/BluetoothLEDeviceFilter.java +++ b/core/java/android/companion/BluetoothLEDeviceFilter.java @@ -21,6 +21,7 @@ import static android.companion.BluetoothDeviceFilterUtils.patternFromString; import static android.companion.BluetoothDeviceFilterUtils.patternToString; import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkState; import android.annotation.NonNull; import android.annotation.Nullable; @@ -31,6 +32,7 @@ import android.bluetooth.le.ScanResult; import android.os.Parcel; import android.provider.OneTimeUseBuilder; import android.text.TextUtils; +import android.util.Log; import com.android.internal.util.BitUtils; import com.android.internal.util.ObjectUtils; @@ -47,6 +49,9 @@ import java.util.regex.Pattern; */ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { + private static final boolean DEBUG = false; + private static final String LOG_TAG = "BluetoothLEDeviceFilter"; + private static final int RENAME_PREFIX_LENGTH_LIMIT = 10; private final Pattern mNamePattern; @@ -57,12 +62,14 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { private final String mRenameSuffix; private final int mRenameBytesFrom; private final int mRenameBytesTo; + private final int mRenameNameFrom; + private final int mRenameNameTo; private final boolean mRenameBytesReverseOrder; private BluetoothLEDeviceFilter(Pattern namePattern, ScanFilter scanFilter, byte[] rawDataFilter, byte[] rawDataFilterMask, String renamePrefix, String renameSuffix, int renameBytesFrom, int renameBytesTo, - boolean renameBytesReverseOrder) { + int renameNameFrom, int renameNameTo, boolean renameBytesReverseOrder) { mNamePattern = namePattern; mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY); mRawDataFilter = rawDataFilter; @@ -71,6 +78,8 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { mRenameSuffix = renameSuffix; mRenameBytesFrom = renameBytesFrom; mRenameBytesTo = renameBytesTo; + mRenameNameFrom = renameNameFrom; + mRenameNameTo = renameNameTo; mRenameBytesReverseOrder = renameBytesReverseOrder; } @@ -129,15 +138,23 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { @Override @Nullable public String getDeviceDisplayName(ScanResult sr) { - if (mRenameBytesFrom < 0) return getDeviceDisplayNameInternal(sr.getDevice()); - final byte[] bytes = sr.getScanRecord().getBytes(); + if (mRenameBytesFrom < 0 && mRenameNameFrom < 0) { + return getDeviceDisplayNameInternal(sr.getDevice()); + } final StringBuilder sb = new StringBuilder(TextUtils.emptyIfNull(mRenamePrefix)); - int startInclusive = mRenameBytesFrom; - int endInclusive = mRenameBytesTo - 1; - int initial = mRenameBytesReverseOrder ? endInclusive : startInclusive; - int step = mRenameBytesReverseOrder ? -1 : 1; - for (int i = initial; startInclusive <= i && i <= endInclusive; i+=step) { - sb.append(Byte.toHexString(bytes[i], true)); + if (mRenameBytesFrom >= 0) { + final byte[] bytes = sr.getScanRecord().getBytes(); + int startInclusive = mRenameBytesFrom; + int endInclusive = mRenameBytesTo - 1; + int initial = mRenameBytesReverseOrder ? endInclusive : startInclusive; + int step = mRenameBytesReverseOrder ? -1 : 1; + for (int i = initial; startInclusive <= i && i <= endInclusive; i += step) { + sb.append(Byte.toHexString(bytes[i], true)); + } + } else { + sb.append( + getDeviceDisplayNameInternal(sr.getDevice()) + .substring(mRenameNameFrom, mRenameNameTo)); } return sb.append(TextUtils.emptyIfNull(mRenameSuffix)).toString(); } @@ -145,9 +162,13 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { /** @hide */ @Override public boolean matches(ScanResult device) { - return matches(device.getDevice()) - && BitUtils.maskedEquals(device.getScanRecord().getBytes(), - mRawDataFilter, mRawDataFilterMask); + boolean result = matches(device.getDevice()) + && (mRawDataFilter == null + || BitUtils.maskedEquals(device.getScanRecord().getBytes(), + mRawDataFilter, mRawDataFilterMask)); + if (DEBUG) Log.i(LOG_TAG, "matches(this = " + this + ", device = " + device + + ") -> " + result); + return result; } private boolean matches(BluetoothDevice device) { @@ -194,6 +215,8 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { dest.writeString(mRenameSuffix); dest.writeInt(mRenameBytesFrom); dest.writeInt(mRenameBytesTo); + dest.writeInt(mRenameNameFrom); + dest.writeInt(mRenameNameTo); dest.writeBoolean(mRenameBytesReverseOrder); } @@ -218,9 +241,16 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { String suffix = in.readString(); int bytesFrom = in.readInt(); int bytesTo = in.readInt(); + int nameFrom = in.readInt(); + int nameTo = in.readInt(); boolean bytesReverseOrder = in.readBoolean(); if (renamePrefix != null) { - builder.setRename(renamePrefix, suffix, bytesFrom, bytesTo, bytesReverseOrder); + if (bytesFrom >= 0) { + builder.setRenameFromBytes(renamePrefix, suffix, bytesFrom, bytesTo, + bytesReverseOrder); + } else { + builder.setRenameFromName(renamePrefix, suffix, nameFrom, nameTo); + } } return builder.build(); } @@ -247,6 +277,8 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { private String mRenameSuffix; private int mRenameBytesFrom = -1; private int mRenameBytesTo; + private int mRenameNameFrom = -1; + private int mRenameNameTo; private boolean mRenameBytesReverseOrder = false; /** @@ -312,17 +344,57 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { * @return self for chaining */ @NonNull - public Builder setRename(@NonNull String prefix, @NonNull String suffix, + public Builder setRenameFromBytes(@NonNull String prefix, @NonNull String suffix, int bytesFrom, int bytesTo, boolean bytesReverseOrder) { - checkNotUsed(); - checkArgument(TextUtils.length(prefix) >= getRenamePrefixLengthLimit(), - "Prefix is too short"); - mRenamePrefix = prefix; - mRenameSuffix = suffix; - checkArgument(bytesFrom < bytesTo, "Byte range must be non-empty"); + checkRenameNotSet(); + checkRangeNotEmpty(bytesFrom, bytesTo); mRenameBytesFrom = bytesFrom; mRenameBytesTo = bytesTo; mRenameBytesReverseOrder = bytesReverseOrder; + return setRename(prefix, suffix); + } + + /** + * Rename the devices shown in the list, using specific characters from the advertised name, + * as well as a custom prefix/suffix around them + * + * Note that the prefix length is limited to {@link #getRenamePrefixLengthLimit} characters + * to ensure that there's enough space to display the byte data + * + * The range of name characters to be displayed cannot be empty + * + * @param prefix to be displayed before the byte data + * @param suffix to be displayed after the byte data + * @param nameFrom the start name character index to be displayed (inclusive) + * @param nameTo the end name character index to be displayed (exclusive) + * @return self for chaining + */ + @NonNull + public Builder setRenameFromName(@NonNull String prefix, @NonNull String suffix, + int nameFrom, int nameTo) { + checkRenameNotSet(); + checkRangeNotEmpty(nameFrom, nameTo); + mRenameNameFrom = nameFrom; + mRenameNameTo = nameTo; + mRenameBytesReverseOrder = false; + return setRename(prefix, suffix); + } + + private void checkRenameNotSet() { + checkState(mRenamePrefix == null, "Renaming rule can only be set once"); + } + + private void checkRangeNotEmpty(int bytesFrom, int bytesTo) { + checkArgument(bytesFrom < bytesTo, "Range must be non-empty"); + } + + @NonNull + private Builder setRename(@NonNull String prefix, @NonNull String suffix) { + checkNotUsed(); + checkArgument(TextUtils.length(prefix) <= getRenamePrefixLengthLimit(), + "Prefix is too long"); + mRenamePrefix = prefix; + mRenameSuffix = suffix; return this; } @@ -334,7 +406,9 @@ public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> { return new BluetoothLEDeviceFilter(mNamePattern, mScanFilter, mRawDataFilter, mRawDataFilterMask, mRenamePrefix, mRenameSuffix, - mRenameBytesFrom, mRenameBytesTo, mRenameBytesReverseOrder); + mRenameBytesFrom, mRenameBytesTo, + mRenameNameFrom, mRenameNameTo, + mRenameBytesReverseOrder); } } } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 4d788e783f34..e50b2a97c2d2 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -22,11 +22,13 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; import android.content.pm.PackageManager; import android.os.Handler; import android.os.RemoteException; +import android.service.notification.NotificationListenerService; import android.util.Log; import java.util.Collections; @@ -195,22 +197,47 @@ public final class CompanionDeviceManager { } } - /** @hide */ - public void requestNotificationAccess() { + /** + * Request notification access for the given component. + * + * The given component must follow the protocol specified in {@link NotificationListenerService} + * + * Only components from the same {@link ComponentName#getPackageName package} as the calling app + * are allowed. + * + * Your app must have an association with a device before calling this API + */ + public void requestNotificationAccess(ComponentName component) { if (!checkFeaturePresent()) { return; } - //TODO implement - throw new UnsupportedOperationException("Not yet implemented"); + try { + mService.requestNotificationAccess(component).send(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (PendingIntent.CanceledException e) { + throw new RuntimeException(e); + } } - /** @hide */ - public boolean haveNotificationAccess() { + /** + * Check whether the given component can access the notifications via a + * {@link NotificationListenerService} + * + * Your app must have an association with a device before calling this API + * + * @param component the name of the component + * @return whether the given component has the notification listener permission + */ + public boolean hasNotificationAccess(ComponentName component) { if (!checkFeaturePresent()) { return false; } - //TODO implement - throw new UnsupportedOperationException("Not yet implemented"); + try { + return mService.hasNotificationAccess(component); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } private boolean checkFeaturePresent() { diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl index 6bbb58da9938..5f73e551d57c 100644 --- a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl +++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl @@ -19,4 +19,5 @@ package android.companion; /** @hide */ interface ICompanionDeviceDiscoveryServiceCallback { oneway void onDeviceSelected(String packageName, int userId, String deviceAddress); + oneway void onDeviceSelectionCancel(); } diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index 7798406c35e5..d3952084116c 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -16,8 +16,10 @@ package android.companion; +import android.app.PendingIntent; import android.companion.IFindDeviceCallback; import android.companion.AssociationRequest; +import android.content.ComponentName; /** * Interface for communication with the core companion device manager service. @@ -32,7 +34,6 @@ interface ICompanionDeviceManager { List<String> getAssociations(String callingPackage, int userId); void disassociate(String deviceMacAddress, String callingPackage); - //TODO add these -// boolean haveNotificationAccess(String packageName); -// oneway void requestNotificationAccess(String packageName); + boolean hasNotificationAccess(in ComponentName component); + PendingIntent requestNotificationAccess(in ComponentName component); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 0da4f8ddbad9..5ca4fa343271 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3424,8 +3424,10 @@ public class Intent implements Parcelable, Cloneable { /** * Deprecated - use ACTION_FACTORY_RESET instead. + * @hide */ @Deprecated + @SystemApi public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR"; /** diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 7fea4a25cab7..ce7894fb3ba1 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -32,7 +32,7 @@ public final class IpSecAlgorithm implements Parcelable { * * <p>Valid lengths for this key are {128, 192, 256}. */ - public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)"; + public static final String CRYPT_AES_CBC = "cbc(aes)"; /** * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new @@ -40,7 +40,7 @@ public final class IpSecAlgorithm implements Parcelable { * * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. */ - public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)"; + public static final String AUTH_HMAC_MD5 = "hmac(md5)"; /** * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in @@ -48,35 +48,35 @@ public final class IpSecAlgorithm implements Parcelable { * * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. */ - public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)"; + public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; /** * SHA256 HMAC Authentication/Integrity Algorithm. * * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256. */ - public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)"; + public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; /** * SHA384 HMAC Authentication/Integrity Algorithm. * * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. */ - public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)"; + public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; /** * SHA512 HMAC Authentication/Integrity Algorithm * * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. */ - public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)"; + public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; /** @hide */ @StringDef({ - ALGO_CRYPT_AES_CBC, - ALGO_AUTH_HMAC_MD5, - ALGO_AUTH_HMAC_SHA1, - ALGO_AUTH_HMAC_SHA256, - ALGO_AUTH_HMAC_SHA512 + CRYPT_AES_CBC, + AUTH_HMAC_MD5, + AUTH_HMAC_SHA1, + AUTH_HMAC_SHA256, + AUTH_HMAC_SHA512 }) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} @@ -164,17 +164,17 @@ public final class IpSecAlgorithm implements Parcelable { private static boolean isTruncationLengthValid(String algo, int truncLenBits) { switch (algo) { - case ALGO_CRYPT_AES_CBC: + case CRYPT_AES_CBC: return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); - case ALGO_AUTH_HMAC_MD5: + case AUTH_HMAC_MD5: return (truncLenBits >= 96 && truncLenBits <= 128); - case ALGO_AUTH_HMAC_SHA1: + case AUTH_HMAC_SHA1: return (truncLenBits >= 96 && truncLenBits <= 160); - case ALGO_AUTH_HMAC_SHA256: + case AUTH_HMAC_SHA256: return (truncLenBits >= 96 && truncLenBits <= 256); - case ALGO_AUTH_HMAC_SHA384: + case AUTH_HMAC_SHA384: return (truncLenBits >= 192 && truncLenBits <= 384); - case ALGO_AUTH_HMAC_SHA512: + case AUTH_HMAC_SHA512: return (truncLenBits >= 256 && truncLenBits <= 512); default: return false; diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 6852beb06529..f8702e2e00e7 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -193,15 +193,44 @@ public final class IpSecManager { * * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * for this user * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved */ public SecurityParameterIndex reserveSecurityParameterIndex( + int direction, InetAddress remoteAddress) + throws ResourceUnavailableException { + try { + return new SecurityParameterIndex( + mService, + direction, + remoteAddress, + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + } catch (SpiUnavailableException unlikely) { + throw new ResourceUnavailableException("No SPIs available"); + } + } + + /** + * Reserve an SPI for traffic bound towards the specified remote address. + * + * <p>If successful, this SPI is guaranteed available until released by a call to {@link + * SecurityParameterIndex#close()}. + * + * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} + * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. + * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. + * @return the reserved SecurityParameterIndex + * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated + * for this user + */ + public SecurityParameterIndex reserveSecurityParameterIndex( int direction, InetAddress remoteAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { + if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { + throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); + } return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); } @@ -249,6 +278,23 @@ public final class IpSecManager { } /** + * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec + * encapsulation of the traffic flowing between the socket and the remote InetAddress of that + * transform. For security reasons, attempts to send traffic to any IP address other than the + * 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)}; + * + * @param socket a socket file descriptor + * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + */ + public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + throws IOException { + applyTransportModeTransform(new ParcelFileDescriptor(socket), transform); + } + + /** * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic). @@ -289,6 +335,20 @@ public final class IpSecManager { removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); } + /** + * Remove a transform from a given stream socket. Once removed, traffic on the socket will not + * be encypted. This allows sockets that have been used for IPsec to be reclaimed for + * communication in the clear in the event socket reuse is desired. This operation will succeed + * regardless of the underlying state of a transform. If a transform is removed, communication + * on all sockets to which that transform was applied will fail until this method is called. + * + * @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) { + removeTransportModeTransform(new ParcelFileDescriptor(socket), transform); + } + /* Call down to activate a transform */ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { diff --git a/core/java/android/net/MatchAllNetworkSpecifier.java b/core/java/android/net/MatchAllNetworkSpecifier.java new file mode 100644 index 000000000000..7aafc93bb4a1 --- /dev/null +++ b/core/java/android/net/MatchAllNetworkSpecifier.java @@ -0,0 +1,80 @@ +/* + * 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; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * MatchAllNetworkSpecifier is a marker class used by NetworkFactory classes to indicate + * that they accept (match) any network specifier in requests. + * + * The class must never be used as part of a network request (those semantics aren't specified). + * + * @hide + */ +public final class MatchAllNetworkSpecifier extends NetworkSpecifier implements Parcelable { + /** + * Utility method which verifies that the ns argument is not a MatchAllNetworkSpecifier and + * throws an IllegalArgumentException if it is. + */ + public static void checkNotMatchAllNetworkSpecifier(NetworkSpecifier ns) { + if (ns instanceof MatchAllNetworkSpecifier) { + throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted"); + } + } + + public boolean satisfiedBy(NetworkSpecifier other) { + /* + * The method is called by a NetworkRequest to see if it is satisfied by a proposed + * network (e.g. as offered by a network factory). Since MatchAllNetweorkSpecifier must + * not be used in network requests this method should never be called. + */ + throw new IllegalStateException( + "MatchAllNetworkSpecifier must not be used in NetworkRequests"); + } + + @Override + public boolean equals(Object o) { + return o instanceof MatchAllNetworkSpecifier; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + // Nothing to write. + } + + public static final Parcelable.Creator<MatchAllNetworkSpecifier> CREATOR = + new Parcelable.Creator<MatchAllNetworkSpecifier>() { + public MatchAllNetworkSpecifier createFromParcel(Parcel in) { + return new MatchAllNetworkSpecifier(); + } + public MatchAllNetworkSpecifier[] newArray(int size) { + return new MatchAllNetworkSpecifier[size]; + } + }; +} diff --git a/core/java/android/net/NetworkBadging.java b/core/java/android/net/NetworkBadging.java index 4409d0a4ce73..b4ef69542bd1 100644 --- a/core/java/android/net/NetworkBadging.java +++ b/core/java/android/net/NetworkBadging.java @@ -56,7 +56,7 @@ public class NetworkBadging { * * @param signalLevel The level returned by {@link WifiManager#calculateSignalLevel(int, int)} * for a network. Must be between 0 and {@link WifiManager#RSSI_LEVELS}-1. - * @param badging {@see ScoredNetwork#Badging}, retrieved from + * @param badging {@see NetworkBadging#Badging}, retrieved from * {@link ScoredNetwork#calculateBadge(int)}. * @param theme The theme for the current application, may be null. * @return Drawable for the given icon @@ -140,7 +140,7 @@ public class NetworkBadging { * <p>This badge should be displayed with the badge signal resource retrieved from * {@link #getBadgedWifiSignalResource(int)}. * - * @param badging {@see ScoredNetwork#Badging} from {@link ScoredNetwork#calculateBadge(int)}. + * @param badging {@see NetworkBadging#Badging} from {@link ScoredNetwork#calculateBadge(int)}. * @return the @DrawableRes for the icon or {@link View#NO_ID} for * {@link NetworkBadging#BADGING_NONE} * @throws IllegalArgumentException for an invalid badging value. diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index a594befbd506..afca0b0e0bd3 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -18,9 +18,11 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; -import android.text.TextUtils; + import com.android.internal.util.BitUtils; +import java.util.Objects; + /** * This class represents the capabilities of a network. This is used both to specify * needs to {@link ConnectivityManager} and when inspecting a network. @@ -33,6 +35,8 @@ import com.android.internal.util.BitUtils; * all cellular based connections are metered and all Wi-Fi based connections are not. */ public final class NetworkCapabilities implements Parcelable { + private static final String TAG = "NetworkCapabilities"; + /** * @hide */ @@ -205,19 +209,6 @@ public final class NetworkCapabilities implements Parcelable { (1 << NET_CAPABILITY_FOREGROUND); /** - * Network specifier for factories which want to match any network specifier - * (NS) in a request. Behavior: - * <li>Empty NS in request matches any network factory NS</li> - * <li>Empty NS in the network factory NS only matches a request with an - * empty NS</li> - * <li>"*" (this constant) NS in the network factory matches requests with - * any NS</li> - * - * @hide - */ - public static final String MATCH_ALL_REQUESTS_NETWORK_SPECIFIER = "*"; - - /** * Network capabilities that are not allowed in NetworkRequests. This exists because the * NetworkFactory / NetworkAgent model does not deal well with the situation where a * capability's presence cannot be known in advance. If such a capability is requested, then we @@ -579,63 +570,56 @@ public final class NetworkCapabilities implements Parcelable { this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps); } - private String mNetworkSpecifier; + private NetworkSpecifier mNetworkSpecifier = null; + /** * Sets the optional bearer specific network specifier. * This has no meaning if a single transport is also not specified, so calling * this without a single transport set will generate an exception, as will * subsequently adding or removing transports after this is set. * </p> - * The interpretation of this {@code String} is bearer specific and bearers that use - * it should document their particulars. For example, Bluetooth may use some sort of - * device id while WiFi could used SSID and/or BSSID. Cellular may use carrier SPN (name) - * or Subscription ID. * - * @param networkSpecifier An {@code String} of opaque format used to specify the bearer - * specific network specifier where the bearer has a choice of - * networks. + * @param networkSpecifier A concrete, parcelable framework class that extends + * NetworkSpecifier. * @return This NetworkCapabilities instance, to facilitate chaining. * @hide */ - public NetworkCapabilities setNetworkSpecifier(String networkSpecifier) { - if (TextUtils.isEmpty(networkSpecifier) == false && Long.bitCount(mTransportTypes) != 1) { + public NetworkCapabilities setNetworkSpecifier(NetworkSpecifier networkSpecifier) { + if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) { throw new IllegalStateException("Must have a single transport specified to use " + "setNetworkSpecifier"); } + mNetworkSpecifier = networkSpecifier; + return this; } /** * Gets the optional bearer specific network specifier. * - * @return The optional {@code String} specifying the bearer specific network specifier. - * See {@link #setNetworkSpecifier}. + * @return The optional {@link NetworkSpecifier} specifying the bearer specific network + * specifier. See {@link #setNetworkSpecifier}. * @hide */ - public String getNetworkSpecifier() { + public NetworkSpecifier getNetworkSpecifier() { return mNetworkSpecifier; } private void combineSpecifiers(NetworkCapabilities nc) { - String otherSpecifier = nc.getNetworkSpecifier(); - if (TextUtils.isEmpty(otherSpecifier)) return; - if (TextUtils.isEmpty(mNetworkSpecifier) == false) { + if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) { throw new IllegalStateException("Can't combine two networkSpecifiers"); } - setNetworkSpecifier(otherSpecifier); + setNetworkSpecifier(nc.mNetworkSpecifier); } + private boolean satisfiedBySpecifier(NetworkCapabilities nc) { - return (TextUtils.isEmpty(mNetworkSpecifier) || - mNetworkSpecifier.equals(nc.mNetworkSpecifier) || - MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(nc.mNetworkSpecifier)); + return mNetworkSpecifier == null || mNetworkSpecifier.satisfiedBy(nc.mNetworkSpecifier) + || nc.mNetworkSpecifier instanceof MatchAllNetworkSpecifier; } + private boolean equalsSpecifier(NetworkCapabilities nc) { - if (TextUtils.isEmpty(mNetworkSpecifier)) { - return TextUtils.isEmpty(nc.mNetworkSpecifier); - } else { - return mNetworkSpecifier.equals(nc.mNetworkSpecifier); - } + return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier); } /** @@ -797,7 +781,7 @@ public final class NetworkCapabilities implements Parcelable { ((int)(mTransportTypes >> 32) * 7) + (mLinkUpBandwidthKbps * 11) + (mLinkDownBandwidthKbps * 13) + - (TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17) + + Objects.hashCode(mNetworkSpecifier) * 17 + (mSignalStrength * 19)); } @@ -811,7 +795,7 @@ public final class NetworkCapabilities implements Parcelable { dest.writeLong(mTransportTypes); dest.writeInt(mLinkUpBandwidthKbps); dest.writeInt(mLinkDownBandwidthKbps); - dest.writeString(mNetworkSpecifier); + dest.writeParcelable((Parcelable) mNetworkSpecifier, flags); dest.writeInt(mSignalStrength); } @@ -825,7 +809,7 @@ public final class NetworkCapabilities implements Parcelable { netCap.mTransportTypes = in.readLong(); netCap.mLinkUpBandwidthKbps = in.readInt(); netCap.mLinkDownBandwidthKbps = in.readInt(); - netCap.mNetworkSpecifier = in.readString(); + netCap.mNetworkSpecifier = in.readParcelable(null); netCap.mSignalStrength = in.readInt(); return netCap; } diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index cb780090c46a..95a8bb472939 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -18,6 +18,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import java.util.Objects; @@ -259,10 +260,27 @@ public class NetworkRequest implements Parcelable { * networks. */ public Builder setNetworkSpecifier(String networkSpecifier) { - if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(networkSpecifier)) { - throw new IllegalArgumentException("Invalid network specifier - must not be '" - + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'"); - } + /* + * A StringNetworkSpecifier does not accept null or empty ("") strings. When network + * specifiers were strings a null string and an empty string were considered equivalent. + * Hence no meaning is attached to a null or empty ("") string. + */ + return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null + : new StringNetworkSpecifier(networkSpecifier)); + } + + /** + * Sets the optional bearer specific network specifier. + * This has no meaning if a single transport is also not specified, so calling + * this without a single transport set will generate an exception, as will + * subsequently adding or removing transports after this is set. + * </p> + * + * @param networkSpecifier A concrete, parcelable framework class that extends + * NetworkSpecifier. + */ + public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) { + MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(networkSpecifier); mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); return this; } diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java new file mode 100644 index 000000000000..87a2b05a4430 --- /dev/null +++ b/core/java/android/net/NetworkSpecifier.java @@ -0,0 +1,36 @@ +/* + * 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; + +/** + * Describes specific properties of a network for use in a {@link NetworkRequest}. + * + * Applications cannot instantiate this class by themselves, but can obtain instances of + * subclasses of this class via other APIs. + */ +public abstract class NetworkSpecifier { + /** @hide */ + public NetworkSpecifier() {} + + /** + * Returns true if a request with this {@link NetworkSpecifier} is satisfied by a network + * with the given NetworkSpecifier. + * + * @hide + */ + public abstract boolean satisfiedBy(NetworkSpecifier other); +} diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java index a664a8bf1ac1..666da0a455fa 100644 --- a/core/java/android/net/ScoredNetwork.java +++ b/core/java/android/net/ScoredNetwork.java @@ -73,29 +73,6 @@ public class ScoredNetwork implements Parcelable { /** A {@link NetworkKey} uniquely identifying this network. */ public final NetworkKey networkKey; - // TODO(b/35323372): Delete these once external references are switched. - /** @deprecated Use {@link NetworkBadging#Badging} instead. */ - @Deprecated - @IntDef({BADGING_NONE, BADGING_SD, BADGING_HD, BADGING_4K}) - @Retention(RetentionPolicy.SOURCE) - public @interface Badging {} - - /** @deprecated Use {@link NetworkBadging#BADGING_NONE} instead. */ - @Deprecated - public static final int BADGING_NONE = 0; - - /** @deprecated Use {@link NetworkBadging#BADGING_SD} instead. */ - @Deprecated - public static final int BADGING_SD = 10; - - /** @deprecated Use {@link NetworkBadging#BADGING_HD} instead. */ - @Deprecated - public static final int BADGING_HD = 20; - - /** @deprecated Use {@link NetworkBadging#BADGING_4K} instead. */ - @Deprecated - public static final int BADGING_4K = 30; - /** * The {@link RssiCurve} representing the scores for this network based on the RSSI. * diff --git a/core/java/android/net/StringNetworkSpecifier.java b/core/java/android/net/StringNetworkSpecifier.java new file mode 100644 index 000000000000..cb7f6bfce713 --- /dev/null +++ b/core/java/android/net/StringNetworkSpecifier.java @@ -0,0 +1,79 @@ +/* + * 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; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.Preconditions; + +import java.util.Objects; + +/** @hide */ +public final class StringNetworkSpecifier extends NetworkSpecifier implements Parcelable { + /** + * Arbitrary string used to pass (additional) information to the network factory. + */ + public final String specifier; + + public StringNetworkSpecifier(String specifier) { + Preconditions.checkStringNotEmpty(specifier); + this.specifier = specifier; + } + + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + return equals(other); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof StringNetworkSpecifier)) return false; + return TextUtils.equals(specifier, ((StringNetworkSpecifier) o).specifier); + } + + @Override + public int hashCode() { + return Objects.hashCode(specifier); + } + + @Override + public String toString() { + return specifier; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(specifier); + } + + public static final Parcelable.Creator<StringNetworkSpecifier> CREATOR = + new Parcelable.Creator<StringNetworkSpecifier>() { + public StringNetworkSpecifier createFromParcel(Parcel in) { + return new StringNetworkSpecifier(in.readString()); + } + public StringNetworkSpecifier[] newArray(int size) { + return new StringNetworkSpecifier[size]; + } + }; +} diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 15bd175949c4..ff0bc69ed325 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -16,9 +16,15 @@ package android.os; +import android.util.ExceptionUtils; import android.util.Log; import android.util.Slog; + import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.FunctionalUtils; +import com.android.internal.util.FunctionalUtils.ThrowingRunnable; +import com.android.internal.util.FunctionalUtils.ThrowingSupplier; + import libcore.io.IoUtils; import java.io.FileDescriptor; @@ -26,7 +32,6 @@ import java.io.FileOutputStream; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Modifier; -import java.util.function.Supplier; /** * Base class for a remotable object, the core part of a lightweight @@ -251,14 +256,23 @@ public class Binder implements IBinder { * Convenience method for running the provided action enclosed in * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} * + * Any exception thrown by the given action will be caught and rethrown after the call to + * {@link #restoreCallingIdentity} + * * @hide */ - public static final void withCleanCallingIdentity(Runnable action) { + public static final void withCleanCallingIdentity(ThrowingRunnable action) { long callingIdentity = clearCallingIdentity(); + Throwable throwableToPropagate = null; try { action.run(); + } catch (Throwable throwable) { + throwableToPropagate = throwable; } finally { restoreCallingIdentity(callingIdentity); + if (throwableToPropagate != null) { + throw ExceptionUtils.propagate(throwableToPropagate); + } } } @@ -266,14 +280,24 @@ public class Binder implements IBinder { * Convenience method for running the provided action enclosed in * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result * + * Any exception thrown by the given action will be caught and rethrown after the call to + * {@link #restoreCallingIdentity} + * * @hide */ - public static final <T> T withCleanCallingIdentity(Supplier<T> action) { + public static final <T> T withCleanCallingIdentity(ThrowingSupplier<T> action) { long callingIdentity = clearCallingIdentity(); + Throwable throwableToPropagate = null; try { return action.get(); + } catch (Throwable throwable) { + throwableToPropagate = throwable; + return null; // overridden by throwing in finally block } finally { restoreCallingIdentity(callingIdentity); + if (throwableToPropagate != null) { + throw ExceptionUtils.propagate(throwableToPropagate); + } } } diff --git a/core/java/android/provider/SettingsStringUtil.java b/core/java/android/provider/SettingsStringUtil.java index 3dfedea18323..a3dc9471a1d0 100644 --- a/core/java/android/provider/SettingsStringUtil.java +++ b/core/java/android/provider/SettingsStringUtil.java @@ -23,6 +23,7 @@ import android.text.TextUtils; import com.android.internal.util.ArrayUtils; +import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.function.Function; @@ -80,6 +81,12 @@ public class SettingsStringUtil { return s; } + public static String addAll(String delimitedElements, Collection<String> elements) { + final ColonDelimitedSet<String> set + = new ColonDelimitedSet.OfStrings(delimitedElements); + return set.addAll(elements) ? set.toString() : delimitedElements; + } + public static String add(String delimitedElements, String element) { final ColonDelimitedSet<String> set = new ColonDelimitedSet.OfStrings(delimitedElements); diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index a4d3fb299734..5e49b8f0553f 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -34,6 +34,8 @@ import android.view.autofill.AutofillManager; import com.android.internal.os.SomeArgs; +import java.util.List; + //TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the //life-cycle (and how state could be maintained on server-side) is well documented. @@ -103,24 +105,22 @@ public abstract class AutofillService extends Service { } @Override - public void onFillRequest(AssistStructure structure, Bundle extras, - IFillCallback callback, int flags) { + public void onFillRequest(FillRequest request, IFillCallback callback) { ICancellationSignal transport = CancellationSignal.createTransport(); try { callback.onCancellable(transport); } catch (RemoteException e) { e.rethrowFromSystemServer(); } - mHandlerCaller.obtainMessageIIOOOO(MSG_ON_FILL_REQUEST, flags, UNUSED_ARG, structure, - CancellationSignal.fromTransport(transport), extras, callback) + mHandlerCaller.obtainMessageOOO(MSG_ON_FILL_REQUEST, request, + CancellationSignal.fromTransport(transport), callback) .sendToTarget(); } @Override - public void onSaveRequest(AssistStructure structure, Bundle extras, - ISaveCallback callback) { - mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure, - extras, callback).sendToTarget(); + public void onSaveRequest(SaveRequest request, ISaveCallback callback) { + mHandlerCaller.obtainMessageOO(MSG_ON_SAVE_REQUEST, request, + callback).sendToTarget(); } }; @@ -131,23 +131,20 @@ public abstract class AutofillService extends Service { break; } case MSG_ON_FILL_REQUEST: { final SomeArgs args = (SomeArgs) msg.obj; - final AssistStructure structure = (AssistStructure) args.arg1; + final FillRequest request = (FillRequest) args.arg1; final CancellationSignal cancellation = (CancellationSignal) args.arg2; - final Bundle extras = (Bundle) args.arg3; - final IFillCallback callback = (IFillCallback) args.arg4; - final FillCallback fillCallback = new FillCallback(callback); - final int flags = msg.arg1; + final IFillCallback callback = (IFillCallback) args.arg3; + final FillCallback fillCallback = new FillCallback(callback, request.getId()); args.recycle(); - onFillRequest(structure, extras, flags, cancellation, fillCallback); + onFillRequest(request, cancellation, fillCallback); break; } case MSG_ON_SAVE_REQUEST: { final SomeArgs args = (SomeArgs) msg.obj; - final AssistStructure structure = (AssistStructure) args.arg1; - final Bundle extras = (Bundle) args.arg2; - final ISaveCallback callback = (ISaveCallback) args.arg3; + final SaveRequest request = (SaveRequest) args.arg1; + final ISaveCallback callback = (ISaveCallback) args.arg2; final SaveCallback saveCallback = new SaveCallback(callback); args.recycle(); - onSaveRequest(structure, extras, saveCallback); + onSaveRequest(request, saveCallback); break; } case MSG_DISCONNECT: { onDisconnected(); @@ -198,6 +195,28 @@ public abstract class AutofillService extends Service { * or {@link FillCallback#onFailure(CharSequence)}) * to notify the result of the request. * + * @param request the {@link FillRequest request} to handle. + * See {@link FillResponse} for examples of multiple-sections requests. + * @param cancellationSignal signal for observing cancellation requests. The system will use + * this to notify you that the fill result is no longer needed and you should stop + * handling this fill request in order to save resources. + * @param callback object used to notify the result of the request. + */ + public void onFillRequest(@NonNull FillRequest request, + @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) { + onFillRequest(request.getStructure(), request.getClientState(), request.getFlags(), + cancellationSignal, callback); + } + + /** + * Called by the Android system do decide if an {@link Activity} can be autofilled by the + * service. + * + * <p>Service must call one of the {@link FillCallback} methods (like + * {@link FillCallback#onSuccess(FillResponse)} + * or {@link FillCallback#onFailure(CharSequence)}) + * to notify the result of the request. + * * @param structure {@link Activity}'s view structure. * @param data bundle containing data passed by the service in a last call to * {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your @@ -211,6 +230,7 @@ public abstract class AutofillService extends Service { * handling this fill request in order to save resources. * @param callback object used to notify the result of the request. */ + @Deprecated public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data, int flags, @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback); @@ -222,6 +242,23 @@ public abstract class AutofillService extends Service { * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)}) * to notify the result of the request. * + * @param request the {@link SaveRequest request} to handle. + * See {@link FillResponse} for examples of multiple-sections requests. + * @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(); + onSaveRequest(contexts.get(contexts.size() - 1).getStructure(), + request.getClientState(), callback); + } + + /** + * Called when user requests service to save the fields of an {@link Activity}. + * + * <p>Service must call one of the {@link SaveCallback} methods (like + * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)}) + * to notify the result of the request. + * * @param structure {@link Activity}'s view structure. * @param data bundle containing data passed by the service in a last call to * {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your @@ -231,6 +268,7 @@ public abstract class AutofillService extends Service { * See {@link FillResponse} for examples of multiple-sections requests. * @param callback object used to notify the result of the request. */ + @Deprecated public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data, @NonNull SaveCallback callback); diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java index e8ad14f55261..a009be805ce7 100644 --- a/core/java/android/service/autofill/FillCallback.java +++ b/core/java/android/service/autofill/FillCallback.java @@ -27,11 +27,13 @@ import android.os.RemoteException; */ public final class FillCallback { private final IFillCallback mCallback; + private final int mRequestId; private boolean mCalled; /** @hide */ - public FillCallback(IFillCallback callback) { + public FillCallback(IFillCallback callback, int requestId) { mCallback = callback; + mRequestId = requestId; } /** @@ -47,7 +49,7 @@ public final class FillCallback { assertNotCalled(); mCalled = true; try { - mCallback.onSuccess(response); + mCallback.onSuccess(response, mRequestId); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java new file mode 100644 index 000000000000..2efa08c00969 --- /dev/null +++ b/core/java/android/service/autofill/FillContext.java @@ -0,0 +1,96 @@ +/* + * 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.NonNull; +import android.app.assist.AssistStructure; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class represents a context for each fill request made via {@link + * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)}. + * It contains a snapshot of the UI state, the view ids that were returned by + * the {@link AutofillService autofill service} as both required to trigger a save + * and optional that can be saved, and the id of the corresponding {@link + * FillRequest}. + * <p> + * This context allows you to inspect the values for the interesting views + * in the context they appeared. Also a reference to the corresponding fill + * request is useful to store meta-data in the client state bundle passed + * to {@link FillResponse.Builder#setClientState(Bundle)} to avoid interpreting + * the UI state again while saving. + */ +public final class FillContext implements Parcelable { + private final int mRequestId; + private final @NonNull AssistStructure mStructure; + + /** @hide */ + public FillContext(int requestId, @NonNull AssistStructure structure) { + mRequestId = requestId; + mStructure = structure; + } + + private FillContext(Parcel parcel) { + this(parcel.readInt(), parcel.readParcelable(null)); + } + + /** + * Gets the id of the {@link FillRequest fill request} this context + * corresponds to. This is useful to associate your custom client + * state with every request to avoid reinterpreting the UI when saving + * user data. + * + * @return The request id. + */ + public int getRequestId() { + return mRequestId; + } + + /** + * @return The screen content. + */ + public AssistStructure getStructure() { + return mStructure; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mRequestId); + parcel.writeParcelable(mStructure, flags); + } + + public static final Parcelable.Creator<FillContext> CREATOR = + new Parcelable.Creator<FillContext>() { + @Override + public FillContext createFromParcel(Parcel parcel) { + return new FillContext(parcel); + } + + @Override + public FillContext[] newArray(int size) { + return new FillContext[size]; + } + }; +} diff --git a/core/java/android/service/autofill/FillRequest.aidl b/core/java/android/service/autofill/FillRequest.aidl new file mode 100644 index 000000000000..2b1a8fea8a5e --- /dev/null +++ b/core/java/android/service/autofill/FillRequest.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 FillRequest; diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java new file mode 100644 index 000000000000..aa6db4d092f2 --- /dev/null +++ b/core/java/android/service/autofill/FillRequest.java @@ -0,0 +1,144 @@ +/* + * 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.NonNull; +import android.annotation.Nullable; +import android.app.assist.AssistStructure; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.Parcel; +import android.os.Parcelable; +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * This class represents a request to an {@link AutofillService autofill provider} + * to interpret the screen and provide information to the system which views are + * interesting for saving and what are the possible ways to fill the inputs on + * the screen if applicable. + * + * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) + */ +public final class FillRequest implements Parcelable { + private static AtomicInteger sIdCounter = new AtomicInteger(); + + /** + * Indicates autofill was explicitly requested by the user. + */ + public static final int FLAG_MANUAL_REQUEST = 0x1; + + /** @hide */ + @IntDef( + flag = true, + value = {FLAG_MANUAL_REQUEST}) + @Retention(RetentionPolicy.SOURCE) + @interface RequestFlags{} + + private final int mId; + private final @RequestFlags int mFlags; + private final @NonNull AssistStructure mStructure; + private final @Nullable Bundle mClientState; + + /** @hide */ + public FillRequest(@NonNull AssistStructure structure, + @Nullable Bundle clientState, @RequestFlags int flags) { + this(sIdCounter.incrementAndGet(), structure, clientState, flags); + } + + private FillRequest(@NonNull Parcel parcel) { + mId = parcel.readInt(); + mStructure = parcel.readParcelable(null); + mClientState = parcel.readBundle(); + mFlags = parcel.readInt(); + } + + private FillRequest(int id, @NonNull AssistStructure structure, + @Nullable Bundle clientState, @RequestFlags int flags) { + mId = id; + mFlags = Preconditions.checkFlagsArgument(flags, FLAG_MANUAL_REQUEST); + mStructure = Preconditions.checkNotNull(structure, "structure"); + mClientState = clientState; + } + + /** + * @return The unique id of this request. + */ + public int getId() { + return mId; + } + + /** + * @return The flags associated with this request. + * + * @see #FLAG_MANUAL_REQUEST + */ + public @RequestFlags int getFlags() { + return mFlags; + } + + /** + * @return The structure capturing the UI state. + */ + public @NonNull AssistStructure getStructure() { + return mStructure; + } + + /** + * Gets the extra client state returned from the last {@link + * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) + * fill request}. + * <p> + * Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) + * save request} is made the client state is cleared. + * + * @return The client state. + */ + public @Nullable Bundle getClientState() { + return mClientState; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mId); + parcel.writeParcelable(mStructure, flags); + parcel.writeBundle(mClientState); + parcel.writeInt(mFlags); + } + + public static final Parcelable.Creator<FillRequest> CREATOR = + new Parcelable.Creator<FillRequest>() { + @Override + public FillRequest createFromParcel(Parcel parcel) { + return new FillRequest(parcel); + } + + @Override + public FillRequest[] newArray(int size) { + return new FillRequest[size]; + } + }; +} diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index eab0d4c882d0..8c8060a608f0 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -132,25 +132,25 @@ import java.util.ArrayList; */ public final class FillResponse implements Parcelable { - private final ArrayList<Dataset> mDatasets; - private final SaveInfo mSaveInfo; - private final Bundle mExtras; - private final RemoteViews mPresentation; - private final IntentSender mAuthentication; - private AutofillId[] mAuthenticationIds; + private final @Nullable ArrayList<Dataset> mDatasets; + private final @Nullable SaveInfo mSaveInfo; + private final @Nullable Bundle mClientState; + private final @Nullable RemoteViews mPresentation; + private final @Nullable IntentSender mAuthentication; + private final @Nullable AutofillId[] mAuthenticationIds; private FillResponse(@NonNull Builder builder) { mDatasets = builder.mDatasets; mSaveInfo = builder.mSaveInfo; - mExtras = builder.mExtras; + mClientState = builder.mCLientState; mPresentation = builder.mPresentation; mAuthentication = builder.mAuthentication; mAuthenticationIds = builder.mAuthenticationIds; } /** @hide */ - public @Nullable Bundle getExtras() { - return mExtras; + public @Nullable Bundle getClientState() { + return mClientState; } /** @hide */ @@ -185,7 +185,7 @@ public final class FillResponse implements Parcelable { public static final class Builder { private ArrayList<Dataset> mDatasets; private SaveInfo mSaveInfo; - private Bundle mExtras; + private Bundle mCLientState; private RemoteViews mPresentation; private IntentSender mAuthentication; private AutofillId[] mAuthenticationIds; @@ -289,23 +289,35 @@ public final class FillResponse implements Parcelable { return this; } + @Deprecated + public Builder setExtras(@Nullable Bundle extras) { + throwIfDestroyed(); + mCLientState = extras; + return this; + } + /** - * Sets a {@link Bundle} that will be passed to subsequent APIs that + * 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)}. + * android.app.assist.AssistStructure, Bundle, 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 * activity, just the latest bundle is passed back to the service. * - * @param extras The response extras. + * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) + * save request} is made the client state is cleared. + * + * @param clientState The custom client state. * @return This builder. */ - public Builder setExtras(Bundle extras) { + public Builder setClientState(@Nullable Bundle clientState) { throwIfDestroyed(); - mExtras = extras; + mCLientState = clientState; return this; } @@ -344,7 +356,7 @@ public final class FillResponse implements Parcelable { return new StringBuilder( "FillResponse: [datasets=").append(mDatasets) .append(", saveInfo=").append(mSaveInfo) - .append(", hasExtras=").append(mExtras != null) + .append(", clientState=").append(mClientState != null) .append(", hasPresentation=").append(mPresentation != null) .append(", hasAuthentication=").append(mAuthentication != null) .append(", authenticationSize=").append(mAuthenticationIds != null @@ -365,7 +377,7 @@ public final class FillResponse implements Parcelable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeTypedArrayList(mDatasets, flags); parcel.writeParcelable(mSaveInfo, flags); - parcel.writeParcelable(mExtras, flags); + parcel.writeParcelable(mClientState, flags); parcel.writeParcelableArray(mAuthenticationIds, flags); parcel.writeParcelable(mAuthentication, flags); parcel.writeParcelable(mPresentation, flags); diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl index a8d86ca1cc79..23a1a3fee47c 100644 --- a/core/java/android/service/autofill/IAutoFillService.aidl +++ b/core/java/android/service/autofill/IAutoFillService.aidl @@ -16,10 +16,10 @@ package android.service.autofill; -import android.app.assist.AssistStructure; -import android.os.Bundle; +import android.service.autofill.FillRequest; import android.service.autofill.IFillCallback; import android.service.autofill.ISaveCallback; +import android.service.autofill.SaveRequest; import com.android.internal.os.IResultReceiver; /** @@ -29,8 +29,6 @@ import com.android.internal.os.IResultReceiver; */ oneway interface IAutoFillService { void onConnectedStateChanged(boolean connected); - void onFillRequest(in AssistStructure structure, in Bundle extras, - in IFillCallback callback, int flags); - void onSaveRequest(in AssistStructure structure, in Bundle extras, - in ISaveCallback callback); + void onFillRequest(in FillRequest request, in IFillCallback callback); + void onSaveRequest(in SaveRequest request, in ISaveCallback callback); } diff --git a/core/java/android/service/autofill/IFillCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl index 2bb3e9acd3e1..688ac84b9cd8 100644 --- a/core/java/android/service/autofill/IFillCallback.aidl +++ b/core/java/android/service/autofill/IFillCallback.aidl @@ -27,6 +27,6 @@ import android.service.autofill.FillResponse; */ interface IFillCallback { void onCancellable(in ICancellationSignal cancellation); - void onSuccess(in FillResponse response); + void onSuccess(in FillResponse response, int requestId); void onFailure(CharSequence message); } diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 4ad0f086691a..258d257813ca 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -140,7 +140,19 @@ public final class SaveInfo implements Parcelable { */ public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 0x10; - private final int mType; + /** @hide */ + @IntDef( + flag = true, + value = { + SAVE_DATA_TYPE_GENERIC, + SAVE_DATA_TYPE_PASSWORD, + SAVE_DATA_TYPE_ADDRESS, + SAVE_DATA_TYPE_CREDIT_CARD, + SAVE_DATA_TYPE_EMAIL_ADDRESS}) + @Retention(RetentionPolicy.SOURCE) + @interface SaveDataType{} + + private final @SaveDataType int mType; private final CharSequence mNegativeActionTitle; private final IntentSender mNegativeActionListener; private final AutofillId[] mRequiredIds; @@ -177,7 +189,7 @@ public final class SaveInfo implements Parcelable { } /** @hide */ - public int getType() { + public @SaveDataType int getType() { return mType; } @@ -191,7 +203,7 @@ public final class SaveInfo implements Parcelable { */ public static final class Builder { - private final int mType; + private final @SaveDataType int mType; private CharSequence mNegativeActionTitle; private IntentSender mNegativeActionListener; // TODO(b/33197203): make mRequiredIds final once addSavableIds() is gone @@ -215,7 +227,7 @@ public final class SaveInfo implements Parcelable { * * @throws IllegalArgumentException if {@code requiredIds} is {@code null} or empty. */ - public Builder(int type, @NonNull AutofillId[] requiredIds) { + public Builder(@SaveDataType int type, @NonNull AutofillId[] requiredIds) { if (false) {// TODO(b/33197203): re-move when clients use it Preconditions.checkArgument(requiredIds != null && requiredIds.length > 0, "must have at least one required id: " + Arrays.toString(requiredIds)); @@ -230,7 +242,7 @@ public final class SaveInfo implements Parcelable { * // TODO(b/33197203): make sure is removed when clients migrated */ @Deprecated - public Builder(int type) { + public Builder(@SaveDataType int type) { this(type, null); } diff --git a/core/java/android/service/autofill/SaveRequest.aidl b/core/java/android/service/autofill/SaveRequest.aidl new file mode 100644 index 000000000000..7789b577714b --- /dev/null +++ b/core/java/android/service/autofill/SaveRequest.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 SaveRequest; diff --git a/core/java/android/service/autofill/SaveRequest.java b/core/java/android/service/autofill/SaveRequest.java new file mode 100644 index 000000000000..9de931542cb9 --- /dev/null +++ b/core/java/android/service/autofill/SaveRequest.java @@ -0,0 +1,92 @@ +/* + * 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.NonNull; +import android.annotation.Nullable; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.Parcel; +import android.os.Parcelable; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a request to an {@link AutofillService + * autofill provider} to save applicable data entered by the user. + * + * @see AutofillService#onSaveRequest(SaveRequest, SaveCallback) + */ +public final class SaveRequest implements Parcelable { + private final @NonNull ArrayList<FillContext> mFillContexts; + private final @Nullable Bundle mClientState; + + /** @hide */ + public SaveRequest(@NonNull ArrayList<FillContext> fillContexts, + @Nullable Bundle clientState) { + mFillContexts = Preconditions.checkNotNull(fillContexts, "fillContexts"); + mClientState = clientState; + } + + private SaveRequest(@NonNull Parcel parcel) { + this(parcel.readTypedArrayList(null), parcel.readBundle()); + } + + /** + * @return The contexts associated with each previous fill request. + */ + public @NonNull List<FillContext> getFillContexts() { + return mFillContexts; + } + + /** + * Gets the extra client state returned from the last {@link + * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)} + * fill request}. + * + * @return The client state. + */ + public @Nullable Bundle getClientState() { + return mClientState; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeTypedArrayList(mFillContexts, flags); + parcel.writeBundle(mClientState); + } + + public static final Creator<SaveRequest> CREATOR = + new Creator<SaveRequest>() { + @Override + public SaveRequest createFromParcel(Parcel parcel) { + return new SaveRequest(parcel); + } + + @Override + public SaveRequest[] newArray(int size) { + return new SaveRequest[size]; + } + }; +} diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 6bbb0ff9861b..98780a7d73d5 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -16,6 +16,8 @@ package android.service.wallpaper; +import android.annotation.Nullable; +import android.app.WallpaperColors; import android.content.res.TypedArray; import android.graphics.Canvas; import android.util.MergedConfiguration; @@ -542,6 +544,24 @@ public abstract class WallpaperService extends Service { */ public void onSurfaceDestroyed(SurfaceHolder holder) { } + + /** + * Notifies the engine that wallpaper colors changed significantly. + * This will trigger a {@link #onComputeWallpaperColors()} call. + */ + public void invalidateColors() { + } + + /** + * Notifies the system about what colors the wallpaper is using. + * You might return null if no color information is available at the moment. In that case + * you might want to call {@link #invalidateColors()} in a near future. + * + * @return List of wallpaper colors and their weights. + */ + public @Nullable WallpaperColors onComputeWallpaperColors() { + return null; + } protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) { out.print(prefix); out.print("mInitializing="); out.print(mInitializing); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index a522652437ba..172ad8da5381 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -109,7 +109,6 @@ import android.widget.FrameLayout; import android.widget.ScrollBarDrawable; import com.android.internal.R; -import com.android.internal.util.Preconditions; import com.android.internal.view.TooltipPopup; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.widget.ScrollBarUtils; @@ -954,41 +953,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; - /** @hide */ - @IntDef({ - AUTOFILL_MODE_INHERIT, - AUTOFILL_MODE_AUTO, - AUTOFILL_MODE_MANUAL - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AutofillMode {} - - /** - * This view inherits the autofill state from it's parent. If there is no parent it is - * {@link #AUTOFILL_MODE_AUTO}. - * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode"> - * {@code android:autofillMode}. - */ - public static final int AUTOFILL_MODE_INHERIT = 0; - - /** - * Allows this view to automatically trigger an autofill request when it get focus. - * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode"> - * {@code android:autofillMode}. - */ - public static final int AUTOFILL_MODE_AUTO = 1; - - /** - * Do not trigger an autofill request if this view is focused. The user can still force - * an autofill request. - * <p>This does not prevent this field from being autofilled if an autofill operation is - * triggered from a different view.</p> - * - * Use with {@link #setAutofillMode(int)} and <a href="#attr_android:autofillMode">{@code - * android:autofillMode}. - */ - public static final int AUTOFILL_MODE_MANUAL = 2; - /** * This view contains an email address. * @@ -2762,7 +2726,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG3_IS_AUTOFILLED * 1 PFLAG3_FINGER_DOWN * 1 PFLAG3_FOCUSED_BY_DEFAULT - * 11 PFLAG3_AUTO_FILL_MODE_MASK + * __ unused * 11 PFLAG3_IMPORTANT_FOR_AUTOFILL * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED @@ -2992,23 +2956,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; /** - * Shift for the place where the autofill mode is stored in the pflags - * - * @see #getAutofillMode() - * @see #setAutofillMode(int) - */ - private static final int PFLAG3_AUTOFILL_MODE_SHIFT = 19; - - /** - * Mask for autofill modes - * - * @see #getAutofillMode() - * @see #setAutofillMode(int) - */ - private static final int PFLAG3_AUTOFILL_MODE_MASK = (AUTOFILL_MODE_INHERIT - | AUTOFILL_MODE_AUTO | AUTOFILL_MODE_MANUAL) << PFLAG3_AUTOFILL_MODE_SHIFT; - - /** * Shift for the bits in {@link #mPrivateFlags3} related to the * "importantForAutofill" attribute. */ @@ -5055,11 +5002,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setFocusedByDefault(a.getBoolean(attr, true)); } break; - case R.styleable.View_autofillMode: - if (a.peekValue(attr) != null) { - setAutofillMode(a.getInt(attr, AUTOFILL_MODE_INHERIT)); - } - break; case R.styleable.View_autofillHints: if (a.peekValue(attr) != null) { CharSequence[] rawHints = null; @@ -6849,8 +6791,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { - if (isAutofillable() && isAttachedToWindow() - && getResolvedAutofillMode() == AUTOFILL_MODE_AUTO) { + if (isAutofillable() && isAttachedToWindow()) { AutofillManager afm = getAutofillManager(); if (afm != null) { if (enter && hasWindowFocus() && isFocused()) { @@ -9159,21 +9100,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Set autofill mode for the view. - * - * @param autofillMode One of {@link #AUTOFILL_MODE_INHERIT}, {@link #AUTOFILL_MODE_AUTO}, - * or {@link #AUTOFILL_MODE_MANUAL}. - * @attr ref android.R.styleable#View_autofillMode - */ - public void setAutofillMode(@AutofillMode int autofillMode) { - Preconditions.checkArgumentInRange(autofillMode, AUTOFILL_MODE_INHERIT, - AUTOFILL_MODE_MANUAL, "autofillMode"); - - mPrivateFlags3 &= ~PFLAG3_AUTOFILL_MODE_MASK; - mPrivateFlags3 |= autofillMode << PFLAG3_AUTOFILL_MODE_SHIFT; - } - - /** * Sets the hints that helps the autofill service to select the appropriate data to fill the * view. * @@ -9810,48 +9736,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Returns the autofill mode for this view. - * - * @return One of {@link #AUTOFILL_MODE_INHERIT}, {@link #AUTOFILL_MODE_AUTO}, or - * {@link #AUTOFILL_MODE_MANUAL}. - * @attr ref android.R.styleable#View_autofillMode - */ - @ViewDebug.ExportedProperty(mapping = { - @ViewDebug.IntToString(from = AUTOFILL_MODE_INHERIT, to = "AUTOFILL_MODE_INHERIT"), - @ViewDebug.IntToString(from = AUTOFILL_MODE_AUTO, to = "AUTOFILL_MODE_AUTO"), - @ViewDebug.IntToString(from = AUTOFILL_MODE_MANUAL, to = "AUTOFILL_MODE_MANUAL") - }) - @AutofillMode - public int getAutofillMode() { - return (mPrivateFlags3 & PFLAG3_AUTOFILL_MODE_MASK) >> PFLAG3_AUTOFILL_MODE_SHIFT; - } - - /** - * Returns the resolved autofill mode for this view. - * - * This is the same as {@link #getAutofillMode()} but if the mode is - * {@link #AUTOFILL_MODE_INHERIT} the parents autofill mode will be returned. - * - * @return One of {@link #AUTOFILL_MODE_AUTO}, or {@link #AUTOFILL_MODE_MANUAL}. If the auto- - * fill mode can not be resolved e.g. {@link #getAutofillMode()} is - * {@link #AUTOFILL_MODE_INHERIT} and the {@link View} is detached - * {@link #AUTOFILL_MODE_AUTO} is returned. - */ - public @AutofillMode int getResolvedAutofillMode() { - @AutofillMode int autofillMode = getAutofillMode(); - - if (autofillMode == AUTOFILL_MODE_INHERIT) { - if (mParent == null) { - return AUTOFILL_MODE_AUTO; - } else { - return mParent.getResolvedAutofillMode(); - } - } else { - return autofillMode; - } - } - - /** * Find the nearest view in the specified direction that can take focus. * This does not actually give focus to that view. * diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index d5aab48afe32..cc11cb8205d5 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -659,17 +659,4 @@ public interface ViewParent { * @return true if the action was consumed by this ViewParent */ public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments); - - /** - * Return the resolved autofill mode. - * - * @return One of {@link View#AUTOFILL_MODE_AUTO}, {@link View#AUTOFILL_MODE_MANUAL} if the - * autofill mode can be resolved. If the autofill mode cannot be resolved - * {@link View#AUTOFILL_MODE_AUTO}. - * - * @see View#getResolvedAutofillMode() - */ - default @View.AutofillMode int getResolvedAutofillMode() { - return View.AUTOFILL_MODE_AUTO; - } } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 41c209cc016a..ec6559cba39b 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -101,7 +101,10 @@ public final class AutofillManager { // Public flags start from the lowest bit /** * Indicates autofill was explicitly requested by the user. + * + * @deprecated Use {@link android.service.autofill.FillRequest#FLAG_MANUAL_REQUEST} */ + @Deprecated public static final int FLAG_MANUAL_REQUEST = 0x1; // Private flags start from the highest bit @@ -760,8 +763,8 @@ public final class AutofillManager { } } - private void requestShowFillUi(IBinder windowToken, AutofillId id, int width, int height, - Rect anchorBounds, IAutofillWindowPresenter presenter) { + private void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id, int width, + int height, Rect anchorBounds, IAutofillWindowPresenter presenter) { final View anchor = findAchorView(windowToken, id); if (anchor == null) { return; @@ -769,9 +772,15 @@ public final class AutofillManager { AutofillCallback callback = null; synchronized (mLock) { - if (getClientLocked().autofillCallbackRequestShowFillUi(anchor, width, height, - anchorBounds, presenter) && mCallback != null) { - callback = mCallback; + if (mSessionId == sessionId) { + AutofillClient client = getClientLocked(); + + if (client != null) { + if (client.autofillCallbackRequestShowFillUi(anchor, width, height, + anchorBounds, presenter) && mCallback != null) { + callback = mCallback; + } + } } } @@ -785,6 +794,23 @@ public final class AutofillManager { } } + private void authenticate(int sessionId, IntentSender intent, Intent fillInIntent) { + synchronized (mLock) { + if (sessionId == mSessionId) { + AutofillClient client = getClientLocked(); + if (client != null) { + client.autofillCallbackAuthenticate(intent, fillInIntent); + } + } + } + } + + private void setState(boolean enabled) { + synchronized (mLock) { + mEnabled = enabled; + } + } + /** * Sets a view as autofilled if the current value is the {code targetValue}. * @@ -804,80 +830,92 @@ public final class AutofillManager { } } - private void handleAutofill(IBinder windowToken, List<AutofillId> ids, + private void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids, List<AutofillValue> values) { - final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken); - if (root == null) { - return; - } - - final int itemCount = ids.size(); - int numApplied = 0; - ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null; + synchronized (mLock) { + if (sessionId != mSessionId) { + return; + } - for (int i = 0; i < itemCount; i++) { - final AutofillId id = ids.get(i); - final AutofillValue value = values.get(i); - final int viewId = id.getViewId(); - final View view = root.findViewByAccessibilityIdTraversal(viewId); - if (view == null) { - Log.w(TAG, "autofill(): no View with id " + viewId); - continue; + final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken); + if (root == null) { + return; } - if (id.isVirtual()) { - if (virtualValues == null) { - // Most likely there will be just one view with virtual children. - virtualValues = new ArrayMap<>(1); - } - SparseArray<AutofillValue> valuesByParent = virtualValues.get(view); - if (valuesByParent == null) { - // We don't know the size yet, but usually it will be just a few fields... - valuesByParent = new SparseArray<>(5); - virtualValues.put(view, valuesByParent); + + final int itemCount = ids.size(); + int numApplied = 0; + ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null; + + for (int i = 0; i < itemCount; i++) { + final AutofillId id = ids.get(i); + final AutofillValue value = values.get(i); + final int viewId = id.getViewId(); + final View view = root.findViewByAccessibilityIdTraversal(viewId); + if (view == null) { + Log.w(TAG, "autofill(): no View with id " + viewId); + continue; } - valuesByParent.put(id.getVirtualChildId(), value); - } else { - synchronized (mLock) { + if (id.isVirtual()) { + if (virtualValues == null) { + // Most likely there will be just one view with virtual children. + virtualValues = new ArrayMap<>(1); + } + SparseArray<AutofillValue> valuesByParent = virtualValues.get(view); + if (valuesByParent == null) { + // We don't know the size yet, but usually it will be just a few fields... + valuesByParent = new SparseArray<>(5); + virtualValues.put(view, valuesByParent); + } + valuesByParent.put(id.getVirtualChildId(), value); + } else { // Mark the view as to be autofilled with 'value' if (mLastAutofilledData == null) { mLastAutofilledData = new ParcelableMap(itemCount - i); } mLastAutofilledData.put(id, value); - } - view.autofill(value); + view.autofill(value); - // Set as autofilled if the values match now, e.g. when the value was updated - // synchronously. - // If autofill happens async, the view is set to autofilled in notifyValueChanged. - setAutofilledIfValuesIs(view, value); + // Set as autofilled if the values match now, e.g. when the value was updated + // synchronously. + // If autofill happens async, the view is set to autofilled in + // notifyValueChanged. + setAutofilledIfValuesIs(view, value); - numApplied++; + numApplied++; + } } - } - if (virtualValues != null) { - for (int i = 0; i < virtualValues.size(); i++) { - final View parent = virtualValues.keyAt(i); - final SparseArray<AutofillValue> childrenValues = virtualValues.valueAt(i); - parent.autofill(childrenValues); - numApplied += childrenValues.size(); + if (virtualValues != null) { + for (int i = 0; i < virtualValues.size(); i++) { + final View parent = virtualValues.keyAt(i); + final SparseArray<AutofillValue> childrenValues = virtualValues.valueAt(i); + parent.autofill(childrenValues); + numApplied += childrenValues.size(); + } } - } - final LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED); - log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount); - log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied); - mMetricsLogger.write(log); + final LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED); + log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount); + log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, + numApplied); + mMetricsLogger.write(log); + } } - private void requestHideFillUi(IBinder windowToken, AutofillId id) { + private void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) { final View anchor = findAchorView(windowToken, id); AutofillCallback callback = null; synchronized (mLock) { - if (getClientLocked().autofillCallbackRequestHideFillUi() && mCallback != null) { - callback = mCallback; + if (mSessionId == sessionId) { + AutofillClient client = getClientLocked(); + + if (client != null) { + if (client.autofillCallbackRequestHideFillUi() && mCallback != null) { + callback = mCallback; + } + } } } @@ -891,12 +929,14 @@ public final class AutofillManager { } } - private void notifyNoFillUi(IBinder windowToken, AutofillId id) { + private void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) { final View anchor = findAchorView(windowToken, id); - AutofillCallback callback; + AutofillCallback callback = null; synchronized (mLock) { - callback = mCallback; + if (mSessionId == sessionId && getClientLocked() != null) { + callback = mCallback; + } } if (callback != null) { @@ -999,73 +1039,57 @@ public final class AutofillManager { public void setState(boolean enabled) { final AutofillManager afm = mAfm.get(); if (afm != null) { - afm.mContext.getMainThreadHandler().post(() -> { - synchronized (afm.mLock) { - afm.mEnabled = enabled; - } - }); + afm.mContext.getMainThreadHandler().post(() -> afm.setState(enabled)); } } @Override - public void autofill(IBinder windowToken, List<AutofillId> ids, + public void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids, List<AutofillValue> values) { // TODO(b/33197203): must keep the dataset so subsequent calls pass the same // dataset.extras to service final AutofillManager afm = mAfm.get(); if (afm != null) { - afm.mContext.getMainThreadHandler().post(() -> - afm.handleAutofill(windowToken, ids, values)); + afm.mContext.getMainThreadHandler().post( + () -> afm.autofill(sessionId, windowToken, ids, values)); } } @Override - public void authenticate(IntentSender intent, Intent fillInIntent) { + public void authenticate(int sessionId, IntentSender intent, Intent fillInIntent) { final AutofillManager afm = mAfm.get(); if (afm != null) { - afm.mContext.getMainThreadHandler().post(() -> { - if (afm.getClientLocked() != null) { - afm.getClientLocked().autofillCallbackAuthenticate(intent, fillInIntent); - } - }); + afm.mContext.getMainThreadHandler().post( + () -> afm.authenticate(sessionId, intent, fillInIntent)); } } @Override - public void requestShowFillUi(IBinder windowToken, AutofillId id, + public void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id, int width, int height, Rect anchorBounds, IAutofillWindowPresenter presenter) { final AutofillManager afm = mAfm.get(); if (afm != null) { - afm.mContext.getMainThreadHandler().post(() -> { - if (afm.getClientLocked() != null) { - afm.requestShowFillUi(windowToken, id, width, - height, anchorBounds, presenter); - } - }); + afm.mContext.getMainThreadHandler().post( + () -> afm.requestShowFillUi(sessionId, windowToken, id, width, height, + anchorBounds, presenter)); } } @Override - public void requestHideFillUi(IBinder windowToken, AutofillId id) { + public void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) { final AutofillManager afm = mAfm.get(); if (afm != null) { - afm.mContext.getMainThreadHandler().post(() -> { - if (afm.getClientLocked() != null) { - afm.requestHideFillUi(windowToken, id); - } - }); + afm.mContext.getMainThreadHandler().post( + () -> afm.requestHideFillUi(sessionId, windowToken, id)); } } @Override - public void notifyNoFillUi(IBinder windowToken, AutofillId id) { + public void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) { final AutofillManager afm = mAfm.get(); if (afm != null) { - afm.mContext.getMainThreadHandler().post(() -> { - if (afm.getClientLocked() != null) { - afm.notifyNoFillUi(windowToken, id); - } - }); + afm.mContext.getMainThreadHandler().post( + () -> afm.notifyNoFillUi(sessionId, windowToken, id)); } } diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index 176eaacb57ae..56f91ed6de9b 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -40,28 +40,29 @@ oneway interface IAutoFillManagerClient { /** * Autofills the activity with the contents of a dataset. */ - void autofill(in IBinder windowToken, in List<AutofillId> ids, in List<AutofillValue> values); + void autofill(int sessionId, in IBinder windowToken, in List<AutofillId> ids, + in List<AutofillValue> values); /** * Authenticates a fill response or a data set. */ - void authenticate(in IntentSender intent, in Intent fillInIntent); + void authenticate(int sessionId, in IntentSender intent, in Intent fillInIntent); /** * Requests showing the fill UI. */ - void requestShowFillUi(in IBinder windowToken, in AutofillId id, int width, + void requestShowFillUi(int sessionId, in IBinder windowToken, in AutofillId id, int width, int height, in Rect anchorBounds, in IAutofillWindowPresenter presenter); /** * Requests hiding the fill UI. */ - void requestHideFillUi(in IBinder windowToken, in AutofillId id); + void requestHideFillUi(int sessionId, in IBinder windowToken, in AutofillId id); /** * Notifies no fill UI will be shown. */ - void notifyNoFillUi(in IBinder windowToken, in AutofillId id); + void notifyNoFillUi(int sessionId, in IBinder windowToken, in AutofillId id); /** * Starts the provided intent sender diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index 2f12e9b5be83..28d9fcf57370 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -155,7 +155,7 @@ public class EditorInfo implements InputType, Parcelable { public static final int IME_ACTION_PREVIOUS = 0x00000007; /** - * Flag of {@link #imeOptions}: used to request that the IME does not update any personalized + * Flag of {@link #imeOptions}: used to request that the IME should not update any personalized * data such as typing history and personalized language model based on what the user typed on * this text editing object. Typical use cases are: * <ul> diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java index 35ffa71de56f..999a908251dd 100644 --- a/core/java/com/android/internal/app/AlertActivity.java +++ b/core/java/com/android/internal/app/AlertActivity.java @@ -67,10 +67,15 @@ public abstract class AlertActivity extends Activity implements DialogInterface @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + return dispatchPopulateAccessibilityEvent(this, event); + } + + public static boolean dispatchPopulateAccessibilityEvent(Activity act, + AccessibilityEvent event) { event.setClassName(Dialog.class.getName()); - event.setPackageName(getPackageName()); + event.setPackageName(act.getPackageName()); - ViewGroup.LayoutParams params = getWindow().getAttributes(); + ViewGroup.LayoutParams params = act.getWindow().getAttributes(); boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) && (params.height == ViewGroup.LayoutParams.MATCH_PARENT); event.setFullScreen(isFullScreen); @@ -86,8 +91,7 @@ public abstract class AlertActivity extends Activity implements DialogInterface * @see #mAlertParams */ protected void setupAlert() { - mAlertParams.apply(mAlert); - mAlert.installContent(); + mAlert.installContent(mAlertParams); } @Override diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 95c291a9e8fe..46cb5461b682 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -247,6 +247,11 @@ public class AlertController { return false; } + public void installContent(AlertParams params) { + params.apply(this); + installContent(); + } + public void installContent() { int contentView = selectContentView(); mWindow.setContentView(contentView); diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java index cb2b0191b883..46f47a31441c 100644 --- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java +++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java @@ -16,6 +16,10 @@ package com.android.internal.app; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.res.Configuration; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -57,6 +61,10 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable { private final boolean mCountryMode; private LayoutInflater mInflater; + private Locale mDisplayLocale = null; + // used to potentially cache a modified Context that uses mDisplayLocale + private Context mContextOverride = null; + public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) { mCountryMode = countryMode; mLocaleOptions = new ArrayList<>(localeOptions.size()); @@ -126,6 +134,31 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable { return position; } + /** + * Overrides the locale used to display localized labels. Setting the locale to null will reset + * the Adapter to use the default locale for the labels. + */ + public void setDisplayLocale(@NonNull Context context, @Nullable Locale locale) { + if (locale == null) { + mDisplayLocale = null; + mContextOverride = null; + } else if (!locale.equals(mDisplayLocale)) { + mDisplayLocale = locale; + final Configuration configOverride = new Configuration(); + configOverride.setLocale(locale); + mContextOverride = context.createConfigurationContext(configOverride); + } + } + + private void setTextTo(@NonNull TextView textView, int resId) { + if (mContextOverride == null) { + textView.setText(resId); + } else { + textView.setText(mContextOverride.getText(resId)); + // If mContextOverride is not null, mDisplayLocale can't be null either. + } + } + @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null && mInflater == null) { @@ -143,15 +176,16 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable { } TextView textView = (TextView) convertView; if (itemType == TYPE_HEADER_SUGGESTED) { - textView.setText(R.string.language_picker_section_suggested); + setTextTo(textView, R.string.language_picker_section_suggested); } else { if (mCountryMode) { - textView.setText(R.string.region_picker_section_all); + setTextTo(textView, R.string.region_picker_section_all); } else { - textView.setText(R.string.language_picker_section_all); + setTextTo(textView, R.string.language_picker_section_all); } } - textView.setTextLocale(Locale.getDefault()); + textView.setTextLocale( + mDisplayLocale != null ? mDisplayLocale : Locale.getDefault()); break; default: // Covers both null, and "reusing" a wrong kind of view diff --git a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java new file mode 100644 index 000000000000..4ce6f609ef73 --- /dev/null +++ b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java @@ -0,0 +1,37 @@ +/* + * 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 com.android.internal.notification; + +import android.content.ComponentName; +import android.content.Intent; + +public final class NotificationAccessConfirmationActivityContract { + private static final ComponentName COMPONENT_NAME = new ComponentName( + "com.android.settings", + "com.android.settings.notification.NotificationAccessConfirmationActivity"); + public static final String EXTRA_USER_ID = "user_id"; + public static final String EXTRA_COMPONENT_NAME = "component_name"; + public static final String EXTRA_PACKAGE_TITLE = "package_title"; + + public static Intent launcherIntent(int userId, ComponentName component, String packageTitle) { + return new Intent() + .setComponent(COMPONENT_NAME) + .putExtra(EXTRA_USER_ID, userId) + .putExtra(EXTRA_COMPONENT_NAME, component) + .putExtra(EXTRA_PACKAGE_TITLE, packageTitle); + } +} diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index 287f68cf5a55..96b443d28abc 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -16,6 +16,8 @@ package com.android.internal.util; +import static com.android.internal.util.ArrayUtils.isEmpty; + import android.annotation.NonNull; import android.annotation.Nullable; @@ -64,7 +66,7 @@ public class CollectionUtils { */ public static @NonNull <I, O> List<O> map(@Nullable List<I> cur, Function<? super I, ? extends O> f) { - if (cur == null || cur.isEmpty()) return Collections.emptyList(); + if (isEmpty(cur)) return Collections.emptyList(); final ArrayList<O> result = new ArrayList<>(); for (int i = 0; i < cur.size(); i++) { result.add(f.apply(cur.get(i))); @@ -73,6 +75,30 @@ public class CollectionUtils { } /** + * {@link #map(List, Function)} + {@link #filter(List, java.util.function.Predicate)} + * + * Calling this is equivalent (but more memory efficient) to: + * + * {@code + * filter( + * map(cur, f), + * i -> { i != null }) + * } + */ + public static @NonNull <I, O> List<O> mapNotNull(@Nullable List<I> cur, + Function<? super I, ? extends O> f) { + if (isEmpty(cur)) return Collections.emptyList(); + final ArrayList<O> result = new ArrayList<>(); + for (int i = 0; i < cur.size(); i++) { + O transformed = f.apply(cur.get(i)); + if (transformed != null) { + result.add(transformed); + } + } + return result; + } + + /** * Returns the given list, or an immutable empty list if the provided list is null * * This can be used to guaranty null-safety without paying the price of extra allocations @@ -94,7 +120,7 @@ public class CollectionUtils { * Returns the elements of the given list that are of type {@code c} */ public static @NonNull <T> List<T> filter(@Nullable List<?> list, Class<T> c) { - if (ArrayUtils.isEmpty(list)) return Collections.emptyList(); + if (isEmpty(list)) return Collections.emptyList(); ArrayList<T> result = null; for (int i = 0; i < list.size(); i++) { final Object item = list.get(i); @@ -120,11 +146,42 @@ public class CollectionUtils { */ public static @Nullable <T> T find(@Nullable List<T> items, java.util.function.Predicate<T> predicate) { - if (ArrayUtils.isEmpty(items)) return null; + if (isEmpty(items)) return null; for (int i = 0; i < items.size(); i++) { final T item = items.get(i); if (predicate.test(item)) return item; } return null; } + + /** + * Similar to {@link List#add}, but with support for list values of {@code null} and + * {@link Collections#emptyList} + */ + public static @NonNull <T> List<T> add(@Nullable List<T> cur, T val) { + if (cur == null || cur == Collections.emptyList()) { + cur = new ArrayList<>(); + } + cur.add(val); + return cur; + } + + /** + * Similar to {@link List#remove}, but with support for list values of {@code null} and + * {@link Collections#emptyList} + */ + public static @NonNull <T> List<T> remove(@Nullable List<T> cur, T val) { + if (isEmpty(cur)) { + return emptyIfNull(cur); + } + cur.remove(val); + return cur; + } + + /** + * @return a list that will not be affected by mutations to the given original list. + */ + public static @NonNull <T> List<T> copyOf(@Nullable List<T> cur) { + return isEmpty(cur) ? Collections.emptyList() : new ArrayList<>(cur); + } } diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java new file mode 100644 index 000000000000..9aeb0415b5fc --- /dev/null +++ b/core/java/com/android/internal/util/FunctionalUtils.java @@ -0,0 +1,48 @@ +/* + * 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 com.android.internal.util; + +import java.util.function.Supplier; + +/** + * Utilities specific to functional programming + */ +public class FunctionalUtils { + private FunctionalUtils() {} + + /** + * An equivalent of {@link Runnable} that allows throwing checked exceptions + * + * This can be used to specify a lambda argument without forcing all the checked exceptions + * to be handled within it + */ + @FunctionalInterface + public interface ThrowingRunnable { + void run() throws Exception; + } + + /** + * An equivalent of {@link Supplier} that allows throwing checked exceptions + * + * This can be used to specify a lambda argument without forcing all the checked exceptions + * to be handled within it + */ + @FunctionalInterface + public interface ThrowingSupplier<T> { + T get() throws Exception; + } +} diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java index 4e6857a72b43..e5d571672ce2 100644 --- a/core/java/com/android/internal/util/Preconditions.java +++ b/core/java/com/android/internal/util/Preconditions.java @@ -49,6 +49,23 @@ public class Preconditions { } /** + * Ensures that an expression checking an argument is true. + * + * @param expression the expression to check + * @param messageTemplate a printf-style message template to use if the check fails; will + * be converted to a string using {@link String#format(String, Object...)} + * @param messageArgs arguments for {@code messageTemplate} + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument(boolean expression, + final String messageTemplate, + final Object... messageArgs) { + if (!expression) { + throw new IllegalArgumentException(String.format(messageTemplate, messageArgs)); + } + } + + /** * Ensures that an string reference passed as a parameter to the calling * method is not empty. * diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 3a03af60efce..0e67d304c66d 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -44,14 +44,6 @@ static jmethodID gBitmap_constructorMethodID; static jmethodID gBitmap_reinitMethodID; static jmethodID gBitmap_getAllocationByteCountMethodID; -static jfieldID gTransferParams_aFieldID; -static jfieldID gTransferParams_bFieldID; -static jfieldID gTransferParams_cFieldID; -static jfieldID gTransferParams_dFieldID; -static jfieldID gTransferParams_eFieldID; -static jfieldID gTransferParams_fFieldID; -static jfieldID gTransferParams_gFieldID; - namespace android { class BitmapWrapper { @@ -742,28 +734,8 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, if (colorType != kN32_SkColorType || xyzD50 == nullptr || transferParameters == nullptr) { colorSpace = GraphicsJNI::colorSpaceForType(colorType); } else { - SkColorSpaceTransferFn p; - p.fA = (float) env->GetDoubleField(transferParameters, gTransferParams_aFieldID); - p.fB = (float) env->GetDoubleField(transferParameters, gTransferParams_bFieldID); - p.fC = (float) env->GetDoubleField(transferParameters, gTransferParams_cFieldID); - p.fD = (float) env->GetDoubleField(transferParameters, gTransferParams_dFieldID); - p.fE = (float) env->GetDoubleField(transferParameters, gTransferParams_eFieldID); - p.fF = (float) env->GetDoubleField(transferParameters, gTransferParams_fFieldID); - p.fG = (float) env->GetDoubleField(transferParameters, gTransferParams_gFieldID); - - SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor); - jfloat* array = env->GetFloatArrayElements(xyzD50, NULL); - xyzMatrix.setFloat(0, 0, array[0]); - xyzMatrix.setFloat(1, 0, array[1]); - xyzMatrix.setFloat(2, 0, array[2]); - xyzMatrix.setFloat(0, 1, array[3]); - xyzMatrix.setFloat(1, 1, array[4]); - xyzMatrix.setFloat(2, 1, array[5]); - xyzMatrix.setFloat(0, 2, array[6]); - xyzMatrix.setFloat(1, 2, array[7]); - xyzMatrix.setFloat(2, 2, array[8]); - env->ReleaseFloatArrayElements(xyzD50, array, 0); - + SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters); + SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50); colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix); } @@ -1635,20 +1607,6 @@ static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlon } /////////////////////////////////////////////////////////////////////////////// -static jclass make_globalref(JNIEnv* env, const char classname[]) -{ - jclass c = env->FindClass(classname); - SkASSERT(c); - return (jclass) env->NewGlobalRef(c); -} - -static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, - const char fieldname[], const char type[]) -{ - jfieldID id = env->GetFieldID(clazz, fieldname, type); - SkASSERT(id); - return id; -} static const JNINativeMethod gBitmapMethods[] = { { "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;", @@ -1706,20 +1664,11 @@ static const JNINativeMethod gBitmapMethods[] = { int register_android_graphics_Bitmap(JNIEnv* env) { - jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters"); - gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D"); - gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D"); - gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D"); - gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D"); - gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D"); - gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D"); - gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D"); - - gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); - gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J"); - gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); - gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); - gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); + gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap")); + gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J"); + gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); + gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V"); + gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I"); return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, NELEM(gBitmapMethods)); } diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index a38acd3cb459..e714671027d6 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -27,6 +27,7 @@ jfieldID gOptions_justBoundsFieldID; jfieldID gOptions_sampleSizeFieldID; jfieldID gOptions_configFieldID; +jfieldID gOptions_colorSpaceFieldID; jfieldID gOptions_premultipliedFieldID; jfieldID gOptions_mutableFieldID; jfieldID gOptions_ditherFieldID; @@ -51,20 +52,6 @@ jmethodID gInsetStruct_constructorMethodID; jclass gBitmapConfig_class; jmethodID gBitmapConfig_nativeToConfigMethodID; -jclass gColorSpace_class; -jmethodID gColorSpace_getMethodID; -jmethodID gColorSpace_matchMethodID; - -jclass gColorSpaceRGB_class; -jmethodID gColorSpaceRGB_constructorMethodID; - -jclass gColorSpace_Named_class; -jfieldID gColorSpace_Named_sRGBFieldID; -jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID; - -jclass gTransferParameters_class; -jmethodID gTransferParameters_constructorMethodID; - using namespace android; jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format) { @@ -243,70 +230,6 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize, needsFineScale(fullSize.height(), decodedSize.height(), sampleSize); } -static jobject getColorSpace(JNIEnv* env, - sk_sp<SkColorSpace>& decodeColorSpace, SkColorType decodeColorType) { - jobject colorSpace = nullptr; - - // No need to match, we know what the output color space will be - if (decodeColorType == kRGBA_F16_SkColorType) { - jobject linearExtendedSRGB = env->GetStaticObjectField( - gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID); - colorSpace = env->CallStaticObjectMethod(gColorSpace_class, - gColorSpace_getMethodID, linearExtendedSRGB); - } else { - // Same here, no need to match - if (decodeColorSpace->isSRGB()) { - jobject sRGB = env->GetStaticObjectField( - gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID); - colorSpace = env->CallStaticObjectMethod(gColorSpace_class, - gColorSpace_getMethodID, sRGB); - } else if (decodeColorSpace.get() != nullptr) { - // Try to match against known RGB color spaces using the CIE XYZ D50 - // conversion matrix and numerical transfer function parameters - SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); - LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix)); - - SkColorSpaceTransferFn transferParams; - // We can only handle numerical transfer functions at the moment - LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams)); - - jobject params = env->NewObject(gTransferParameters_class, - gTransferParameters_constructorMethodID, - transferParams.fA, transferParams.fB, transferParams.fC, - transferParams.fD, transferParams.fE, transferParams.fF, - transferParams.fG); - - jfloatArray xyzArray = env->NewFloatArray(9); - jfloat xyz[9] = { - xyzMatrix.getFloat(0, 0), - xyzMatrix.getFloat(1, 0), - xyzMatrix.getFloat(2, 0), - xyzMatrix.getFloat(0, 1), - xyzMatrix.getFloat(1, 1), - xyzMatrix.getFloat(2, 1), - xyzMatrix.getFloat(0, 2), - xyzMatrix.getFloat(1, 2), - xyzMatrix.getFloat(2, 2) - }; - env->SetFloatArrayRegion(xyzArray, 0, 9, xyz); - - colorSpace = env->CallStaticObjectMethod(gColorSpace_class, - gColorSpace_matchMethodID, xyzArray, params); - - if (colorSpace == nullptr) { - // We couldn't find an exact match, let's create a new color space - // instance with the 3x3 conversion matrix and transfer function - colorSpace = env->NewObject(gColorSpaceRGB_class, - gColorSpaceRGB_constructorMethodID, - env->NewStringUTF("Unknown"), xyzArray, params); - } - - env->DeleteLocalRef(xyzArray); - } - } - return colorSpace; -} - static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) { // This function takes ownership of the input stream. Since the SkAndroidCodec // will take ownership of the stream, we don't necessarily need to take ownership @@ -323,6 +246,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding float scale = 1.0f; bool requireUnpremultiplied = false; jobject javaBitmap = NULL; + sk_sp<SkColorSpace> prefColorSpace = nullptr; // Update with options supplied by the client. if (options != NULL) { @@ -346,6 +270,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig); + jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID); + prefColorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace); isHardware = GraphicsJNI::isHardwareConfig(env, jconfig); isMutable = env->GetBooleanField(options, gOptions_mutableFieldID); requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID); @@ -399,7 +325,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding // Set the decode colorType SkColorType decodeColorType = codec->computeOutputColorType(prefColorType); - sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(decodeColorType); + sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace( + decodeColorType, prefColorSpace); // Set the options and return if the client only wants the size. if (options != NULL) { @@ -427,7 +354,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding env->SetObjectField(options, gOptions_outConfigFieldID, config); env->SetObjectField(options, gOptions_outColorSpaceFieldID, - getColorSpace(env, decodeColorSpace, decodeColorType)); + GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType)); if (onlyDecodeSize) { return nullptr; @@ -795,6 +722,8 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I"); gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig", "Landroid/graphics/Bitmap$Config;"); + gOptions_colorSpaceFieldID = GetFieldIDOrDie(env, options_class, "inPreferredColorSpace", + "Landroid/graphics/ColorSpace;"); gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z"); gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z"); gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z"); @@ -827,29 +756,6 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class, "nativeToConfig", "(I)Landroid/graphics/Bitmap$Config;"); - gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace")); - gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, - "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;"); - gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match", - "([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;"); - - gColorSpaceRGB_class = MakeGlobalRefOrDie(env, - FindClassOrDie(env, "android/graphics/ColorSpace$Rgb")); - gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class, - "<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V"); - - gColorSpace_Named_class = MakeGlobalRefOrDie(env, - FindClassOrDie(env, "android/graphics/ColorSpace$Named")); - gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env, - gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;"); - gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env, - gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;"); - - gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, - "android/graphics/ColorSpace$Rgb$TransferParameters")); - gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class, - "<init>", "(DDDDDDD)V"); - return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory", gMethods, NELEM(gMethods)); } diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h index 76db41dca53f..1ee49fa0af77 100644 --- a/core/jni/android/graphics/BitmapFactory.h +++ b/core/jni/android/graphics/BitmapFactory.h @@ -8,6 +8,7 @@ extern jclass gOptions_class; extern jfieldID gOptions_justBoundsFieldID; extern jfieldID gOptions_sampleSizeFieldID; extern jfieldID gOptions_configFieldID; +extern jfieldID gOptions_colorSpaceFieldID; extern jfieldID gOptions_premultipliedFieldID; extern jfieldID gOptions_ditherFieldID; extern jfieldID gOptions_purgeableFieldID; @@ -17,9 +18,14 @@ extern jfieldID gOptions_preferQualityOverSpeedFieldID; extern jfieldID gOptions_widthFieldID; extern jfieldID gOptions_heightFieldID; extern jfieldID gOptions_mimeFieldID; +extern jfieldID gOptions_outConfigFieldID; +extern jfieldID gOptions_outColorSpaceFieldID; extern jfieldID gOptions_mCancelID; extern jfieldID gOptions_bitmapFieldID; +extern jclass gBitmapConfig_class; +extern jmethodID gBitmapConfig_nativeToConfigMethodID; + jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format); jobject decodeBitmap(JNIEnv* env, void* data, size_t size); diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 3247851a0ede..5022b22e8ea7 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -132,11 +132,14 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in bool requireUnpremul = false; jobject javaBitmap = NULL; bool isHardware = false; + sk_sp<SkColorSpace> colorSpace = nullptr; // Update the default options with any options supplied by the client. if (NULL != options) { sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig); + jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID); + colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace); isHardware = GraphicsJNI::isHardwareConfig(env, jconfig); requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID); javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID); @@ -148,8 +151,16 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in env->SetIntField(options, gOptions_widthFieldID, -1); env->SetIntField(options, gOptions_heightFieldID, -1); env->SetObjectField(options, gOptions_mimeFieldID, 0); + env->SetObjectField(options, gOptions_outConfigFieldID, 0); + env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0); } + SkBitmapRegionDecoder* brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); + + SkColorType decodeColorType = brd->computeOutputColorType(colorType); + sk_sp<SkColorSpace> decodeColorSpace = brd->computeOutputColorSpace( + decodeColorType, colorSpace); + // Recycle a bitmap if possible. android::Bitmap* recycledBitmap = nullptr; size_t recycledBytes = 0; @@ -168,17 +179,16 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in if (javaBitmap) { allocator = &recycleAlloc; // We are required to match the color type of the recycled bitmap. - colorType = recycledBitmap->info().colorType(); + decodeColorType = recycledBitmap->info().colorType(); } else { allocator = &heapAlloc; } // Decode the region. SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight); - SkBitmapRegionDecoder* brd = - reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); SkBitmap bitmap; - if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize, colorType, requireUnpremul)) { + if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize, + decodeColorType, requireUnpremul, decodeColorSpace)) { return nullObjectReturn("Failed to decode region."); } @@ -186,11 +196,23 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in if (NULL != options) { env->SetIntField(options, gOptions_widthFieldID, bitmap.width()); env->SetIntField(options, gOptions_heightFieldID, bitmap.height()); + env->SetObjectField(options, gOptions_mimeFieldID, encodedFormatToString(env, (SkEncodedImageFormat)brd->getEncodedFormat())); if (env->ExceptionCheck()) { return nullObjectReturn("OOM in encodedFormatToString()"); } + + jint configID = GraphicsJNI::colorTypeToLegacyBitmapConfig(decodeColorType); + if (isHardware) { + configID = GraphicsJNI::kHardware_LegacyBitmapConfig; + } + jobject config = env->CallStaticObjectMethod(gBitmapConfig_class, + gBitmapConfig_nativeToConfigMethodID, configID); + env->SetObjectField(options, gOptions_outConfigFieldID, config); + + env->SetObjectField(options, gOptions_outColorSpaceFieldID, + GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType)); } // If we may have reused a bitmap, we need to indicate that the pixels have changed. diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index e66587a9d8fe..452d0a941c7b 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -6,6 +6,7 @@ #include "jni.h" #include "JNIHelp.h" #include "GraphicsJNI.h" +#include "core_jni_helpers.h" #include "SkCanvas.h" #include "SkMath.h" @@ -17,6 +18,8 @@ #include <Caches.h> #include <TextureCache.h> +using namespace android; + void doThrowNPE(JNIEnv* env) { jniThrowNullPointerException(env, NULL); } @@ -178,6 +181,32 @@ static jclass gVMRuntime_class; static jmethodID gVMRuntime_newNonMovableArray; static jmethodID gVMRuntime_addressOf; +static jfieldID gTransferParams_aFieldID; +static jfieldID gTransferParams_bFieldID; +static jfieldID gTransferParams_cFieldID; +static jfieldID gTransferParams_dFieldID; +static jfieldID gTransferParams_eFieldID; +static jfieldID gTransferParams_fFieldID; +static jfieldID gTransferParams_gFieldID; + +static jclass gColorSpace_class; +static jfieldID gColorSpace_IlluminantD50FieldID; +static jmethodID gColorSpace_adaptMethodID; +static jmethodID gColorSpace_getMethodID; +static jmethodID gColorSpace_matchMethodID; + +static jclass gColorSpaceRGB_class; +static jmethodID gColorSpaceRGB_getTransferParametersMethodID; +static jmethodID gColorSpaceRGB_getTransformMethodID; +static jmethodID gColorSpaceRGB_constructorMethodID; + +static jclass gColorSpace_Named_class; +static jfieldID gColorSpace_Named_sRGBFieldID; +static jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID; + +static jclass gTransferParameters_class; +static jmethodID gTransferParameters_constructorMethodID; + /////////////////////////////////////////////////////////////////////////////// void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B) @@ -328,7 +357,7 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { } void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) { - android::bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap); + bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap); } SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject jbitmap) { @@ -464,6 +493,125 @@ bool GraphicsJNI::isColorSpaceSRGB(SkColorSpace* colorSpace) { return colorSpace == nullptr || colorSpace->isSRGB(); } +SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) { + SkColorSpaceTransferFn p; + p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID); + p.fB = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID); + p.fC = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID); + p.fD = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID); + p.fE = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID); + p.fF = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID); + p.fG = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID); + return p; +} + +SkMatrix44 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) { + SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor); + jfloat* array = env->GetFloatArrayElements(xyzD50, NULL); + xyzMatrix.setFloat(0, 0, array[0]); + xyzMatrix.setFloat(1, 0, array[1]); + xyzMatrix.setFloat(2, 0, array[2]); + xyzMatrix.setFloat(0, 1, array[3]); + xyzMatrix.setFloat(1, 1, array[4]); + xyzMatrix.setFloat(2, 1, array[5]); + xyzMatrix.setFloat(0, 2, array[6]); + xyzMatrix.setFloat(1, 2, array[7]); + xyzMatrix.setFloat(2, 2, array[8]); + env->ReleaseFloatArrayElements(xyzD50, array, 0); + return xyzMatrix; +} + +sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorSpace) { + if (colorSpace == nullptr) return nullptr; + if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) { + doThrowIAE(env, "The color space must be an RGB color space"); + } + + jobject transferParams = env->CallObjectMethod(colorSpace, + gColorSpaceRGB_getTransferParametersMethodID); + if (transferParams == nullptr) { + doThrowIAE(env, "The color space must use an ICC parametric transfer function"); + } + + jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class, + gColorSpace_IlluminantD50FieldID); + jobject colorSpaceD50 = env->CallStaticObjectMethod(gColorSpace_class, + gColorSpace_adaptMethodID, colorSpace, illuminantD50); + + jfloatArray xyzD50 = (jfloatArray) env->CallObjectMethod(colorSpaceD50, + gColorSpaceRGB_getTransformMethodID); + + SkMatrix44 xyzMatrix = getNativeXYZMatrix(env, xyzD50); + SkColorSpaceTransferFn transferFunction = getNativeTransferParameters(env, transferParams); + + return SkColorSpace::MakeRGB(transferFunction, xyzMatrix); +} + + +jobject GraphicsJNI::getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace, + SkColorType decodeColorType) { + jobject colorSpace = nullptr; + + // No need to match, we know what the output color space will be + if (decodeColorType == kRGBA_F16_SkColorType) { + jobject linearExtendedSRGB = env->GetStaticObjectField( + gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID); + colorSpace = env->CallStaticObjectMethod(gColorSpace_class, + gColorSpace_getMethodID, linearExtendedSRGB); + } else { + // Same here, no need to match + if (decodeColorSpace->isSRGB()) { + jobject sRGB = env->GetStaticObjectField( + gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID); + colorSpace = env->CallStaticObjectMethod(gColorSpace_class, + gColorSpace_getMethodID, sRGB); + } else if (decodeColorSpace.get() != nullptr) { + // Try to match against known RGB color spaces using the CIE XYZ D50 + // conversion matrix and numerical transfer function parameters + SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); + LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix)); + + SkColorSpaceTransferFn transferParams; + // We can only handle numerical transfer functions at the moment + LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams)); + + jobject params = env->NewObject(gTransferParameters_class, + gTransferParameters_constructorMethodID, + transferParams.fA, transferParams.fB, transferParams.fC, + transferParams.fD, transferParams.fE, transferParams.fF, + transferParams.fG); + + jfloatArray xyzArray = env->NewFloatArray(9); + jfloat xyz[9] = { + xyzMatrix.getFloat(0, 0), + xyzMatrix.getFloat(1, 0), + xyzMatrix.getFloat(2, 0), + xyzMatrix.getFloat(0, 1), + xyzMatrix.getFloat(1, 1), + xyzMatrix.getFloat(2, 1), + xyzMatrix.getFloat(0, 2), + xyzMatrix.getFloat(1, 2), + xyzMatrix.getFloat(2, 2) + }; + env->SetFloatArrayRegion(xyzArray, 0, 9, xyz); + + colorSpace = env->CallStaticObjectMethod(gColorSpace_class, + gColorSpace_matchMethodID, xyzArray, params); + + if (colorSpace == nullptr) { + // We couldn't find an exact match, let's create a new color space + // instance with the 3x3 conversion matrix and transfer function + colorSpace = env->NewObject(gColorSpaceRGB_class, + gColorSpaceRGB_constructorMethodID, + env->NewStringUTF("Unknown"), xyzArray, params); + } + + env->DeleteLocalRef(xyzArray); + } + } + return colorSpace; +} + /////////////////////////////////////////////////////////////////////////////// bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { mStorage = android::Bitmap::allocateHeapBitmap(bitmap, ctable); @@ -577,74 +725,97 @@ bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) //////////////////////////////////////////////////////////////////////////////// -static jclass make_globalref(JNIEnv* env, const char classname[]) -{ - jclass c = env->FindClass(classname); - SkASSERT(c); - return (jclass) env->NewGlobalRef(c); -} - -static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, - const char fieldname[], const char type[]) -{ - jfieldID id = env->GetFieldID(clazz, fieldname, type); - SkASSERT(id); - return id; -} - int register_android_graphics_Graphics(JNIEnv* env) { jmethodID m; jclass c; - gRect_class = make_globalref(env, "android/graphics/Rect"); - gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I"); - gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I"); - gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I"); - gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I"); + gRect_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Rect")); + gRect_leftFieldID = GetFieldIDOrDie(env, gRect_class, "left", "I"); + gRect_topFieldID = GetFieldIDOrDie(env, gRect_class, "top", "I"); + gRect_rightFieldID = GetFieldIDOrDie(env, gRect_class, "right", "I"); + gRect_bottomFieldID = GetFieldIDOrDie(env, gRect_class, "bottom", "I"); - gRectF_class = make_globalref(env, "android/graphics/RectF"); - gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F"); - gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F"); - gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F"); - gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F"); + gRectF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/RectF")); + gRectF_leftFieldID = GetFieldIDOrDie(env, gRectF_class, "left", "F"); + gRectF_topFieldID = GetFieldIDOrDie(env, gRectF_class, "top", "F"); + gRectF_rightFieldID = GetFieldIDOrDie(env, gRectF_class, "right", "F"); + gRectF_bottomFieldID = GetFieldIDOrDie(env, gRectF_class, "bottom", "F"); - gPoint_class = make_globalref(env, "android/graphics/Point"); - gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I"); - gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I"); + gPoint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Point")); + gPoint_xFieldID = GetFieldIDOrDie(env, gPoint_class, "x", "I"); + gPoint_yFieldID = GetFieldIDOrDie(env, gPoint_class, "y", "I"); - gPointF_class = make_globalref(env, "android/graphics/PointF"); - gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F"); - gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F"); + gPointF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/PointF")); + gPointF_xFieldID = GetFieldIDOrDie(env, gPointF_class, "x", "F"); + gPointF_yFieldID = GetFieldIDOrDie(env, gPointF_class, "y", "F"); - gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder"); - gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(J)V"); + gBitmapRegionDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/BitmapRegionDecoder")); + gBitmapRegionDecoder_constructorMethodID = GetMethodIDOrDie(env, gBitmapRegionDecoder_class, "<init>", "(J)V"); - gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config"); - gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class, - "nativeInt", "I"); + gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap$Config")); + gBitmapConfig_nativeInstanceID = GetFieldIDOrDie(env, gBitmapConfig_class, "nativeInt", "I"); - gCanvas_class = make_globalref(env, "android/graphics/Canvas"); - gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvasWrapper", "J"); + gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas")); + gCanvas_nativeInstanceID = GetFieldIDOrDie(env, gCanvas_class, "mNativeCanvasWrapper", "J"); - gPicture_class = make_globalref(env, "android/graphics/Picture"); - gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "J"); + gPicture_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Picture")); + gPicture_nativeInstanceID = GetFieldIDOrDie(env, gPicture_class, "mNativePicture", "J"); - gRegion_class = make_globalref(env, "android/graphics/Region"); - gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "J"); - gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>", - "(JI)V"); + gRegion_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Region")); + gRegion_nativeInstanceID = GetFieldIDOrDie(env, gRegion_class, "mNativeRegion", "J"); + gRegion_constructorMethodID = GetMethodIDOrDie(env, gRegion_class, "<init>", "(JI)V"); c = env->FindClass("java/lang/Byte"); gByte_class = (jclass) env->NewGlobalRef( env->GetStaticObjectField(c, env->GetStaticFieldID(c, "TYPE", "Ljava/lang/Class;"))); - gVMRuntime_class = make_globalref(env, "dalvik/system/VMRuntime"); + gVMRuntime_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "dalvik/system/VMRuntime")); m = env->GetStaticMethodID(gVMRuntime_class, "getRuntime", "()Ldalvik/system/VMRuntime;"); gVMRuntime = env->NewGlobalRef(env->CallStaticObjectMethod(gVMRuntime_class, m)); - gVMRuntime_newNonMovableArray = env->GetMethodID(gVMRuntime_class, "newNonMovableArray", + gVMRuntime_newNonMovableArray = GetMethodIDOrDie(env, gVMRuntime_class, "newNonMovableArray", "(Ljava/lang/Class;I)Ljava/lang/Object;"); - gVMRuntime_addressOf = env->GetMethodID(gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J"); + gVMRuntime_addressOf = GetMethodIDOrDie(env, gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J"); + + jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters"); + gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D"); + gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D"); + gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D"); + gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D"); + gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D"); + gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D"); + gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D"); + + gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace")); + gColorSpace_IlluminantD50FieldID = GetStaticFieldIDOrDie(env, + gColorSpace_class, "ILLUMINANT_D50", "[F"); + gColorSpace_adaptMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "adapt", + "(Landroid/graphics/ColorSpace;[F)Landroid/graphics/ColorSpace;"); + gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, + "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;"); + gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match", + "([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;"); + + gColorSpaceRGB_class = MakeGlobalRefOrDie(env, + FindClassOrDie(env, "android/graphics/ColorSpace$Rgb")); + gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class, + "<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V"); + gColorSpaceRGB_getTransferParametersMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class, + "getTransferParameters", "()Landroid/graphics/ColorSpace$Rgb$TransferParameters;"); + gColorSpaceRGB_getTransformMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class, + "getTransform", "()[F"); + + gColorSpace_Named_class = MakeGlobalRefOrDie(env, + FindClassOrDie(env, "android/graphics/ColorSpace$Named")); + gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env, + gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;"); + gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env, + gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;"); + + gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, + "android/graphics/ColorSpace$Rgb$TransferParameters")); + gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class, + "<init>", "(DDDDDDD)V"); return 0; } diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 7d7c88159a55..7fbea2589730 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -10,6 +10,7 @@ #include "SkPoint.h" #include "SkRect.h" #include "SkColorSpace.h" +#include "SkMatrix44.h" #include <jni.h> #include <hwui/Canvas.h> #include <hwui/Bitmap.h> @@ -112,6 +113,13 @@ public: static sk_sp<SkColorSpace> linearColorSpace(); static sk_sp<SkColorSpace> colorSpaceForType(SkColorType type); static bool isColorSpaceSRGB(SkColorSpace* colorSpace); + + static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams); + static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50); + static sk_sp<SkColorSpace> getNativeColorSpace(JNIEnv* env, jobject colorSpace); + + static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace, + SkColorType decodeColorType); }; class HeapAllocator : public SkBRDAllocator { diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index 1883ecb9684a..9491a1ecdad3 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -59,7 +59,7 @@ static jint android_os_VintfObject_verify(JNIEnv *env, jclass clazz, jobjectArra cPackageInfo[i] = cString; env->ReleaseStringUTFChars(element, cString); } - int32_t status = VintfObject::CheckCompatibility(cPackageInfo, false /* mount */); + int32_t status = VintfObject::CheckCompatibility(cPackageInfo); return status; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 000c8c434ded..8869593c2194 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3556,6 +3556,11 @@ android:process=":ui"> </activity> + <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity" + android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" + android:excludeFromRecents="true"> + </activity> + <receiver android:name="com.android.server.BootReceiver" android:systemUserOnly="true"> <intent-filter android:priority="1000"> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 67f6d190e586..4fb21fae8908 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1371,6 +1371,22 @@ Corresponds to {@link android.view.inputmethod.EditorInfo#IME_ACTION_PREVIOUS}. --> <flag name="actionPrevious" value="0x00000007" /> + <!-- Used to request that the IME should not update any personalized data such as typing + history and personalized language model based on what the user typed on this text + editing object. Typical use cases are: + <ul> + <li>When the application is in a special mode, where user's activities are expected + to be not recorded in the application's history. Some web browsers and chat + applications may have this kind of modes.</li> + <li>When storing typing history does not make much sense. Specifying this flag in + typing games may help to avoid typing history from being filled up with words that + the user is less likely to type in their daily life. Another example is that when + the application already knows that the expected input is not a valid word (e.g. a + promotion code that is not a valid word in any natural language).</li> + </ul> + <p>Applications need to be aware that the flag is not a guarantee, and some IMEs may + not respect it.</p> --> + <flag name="flagNoPersonalizedLearning" value="0x1000000" /> <!-- Used to request that the IME never go into fullscreen mode. Applications need to be aware that the flag is not a guarantee, and not all IMEs will respect it. @@ -2304,18 +2320,7 @@ <enum name="auto" value="0x00000010" /> </attr> - <!-- Controls the autofill behavior for this view. --> - <attr name="autofillMode"> - <!-- Inherit the behavior from the parent. If there is no parent it is auto. This is the - default value for this attribute.--> - <enum name="inherit" value="0" /> - <!-- Allows this view to automatically trigger an autofill request when it get focus. - --> - <enum name="auto" value="1" /> - <!-- Do not trigger an autofill request when this view is focused. The user can still - manually force an autofill request for this view. --> - <enum name="manual" value="2" /> - </attr> + <attr name="__removed3" /> <!-- Describes the content of a view so that a autofill service can fill in the appropriate data. Multiple hints can be combined in a comma separated list or an array of strings diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d6ed1786e760..213d6cafa72b 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2797,7 +2797,7 @@ <public name="numericModifiers" /> <public name="fontProviderAuthority" /> <public name="fontProviderQuery" /> - <public name="autofillMode" /> + <public name="__removed3" /> <public name="primaryContentAlpha" /> <public name="secondaryContentAlpha" /> <public name="requiredFeature" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d2ec274e7507..f2da8457601c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -19,6 +19,9 @@ <!-- Private symbols that we need to reference from framework code. See frameworks/base/core/res/MakeJavaSymbols.sed for how to easily generate this. + + Can be referenced in java code as: com.android.internal.R.<type>.<name> + and in layout xml as: "@*android:<type>/<name>" --> <java-symbol type="id" name="account_name" /> <java-symbol type="id" name="account_row_icon" /> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index ec653d0849b1..7f07f03dde61 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -40,6 +40,7 @@ applications that come with the platform <privapp-permissions package="com.android.defcontainer"> <permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/> + <permission name="android.permission.ALLOCATE_AGGRESSIVE"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.WRITE_MEDIA_STORAGE"/> </privapp-permissions> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 919068500e6f..7a8e4873a7c9 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -916,9 +916,8 @@ 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, - * {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is - * ignored if the config is not {@link Config#ARGB_8888}. + * @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. * * @throws IllegalArgumentException if the width or height are <= 0, if * Config is Config.HARDWARE (because hardware bitmaps are always @@ -968,9 +967,8 @@ 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, - * {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is - * ignored if the config is not {@link Config#ARGB_8888}. + * @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. * * @throws IllegalArgumentException if the width or height are <= 0, if * Config is Config.HARDWARE (because hardware bitmaps are always diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index ceedc1fdb360..3b272c8ddec7 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -43,7 +43,6 @@ public class BitmapFactory { * the same result from the decoder as if null were passed. */ public Options() { - inDither = false; inScaled = true; inPremultiplied = true; } @@ -114,8 +113,8 @@ public class BitmapFactory { /** * If set to true, the decoder will return null (no bitmap), but - * the out... fields will still be set, allowing the caller to query - * the bitmap without having to allocate the memory for its pixels. + * the <code>out...</code> fields will still be set, allowing the caller to + * query the bitmap without having to allocate the memory for its pixels. */ public boolean inJustDecodeBounds; @@ -144,6 +143,35 @@ public class BitmapFactory { public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888; /** + * <p>If this is non-null, the decoder will try to decode into this + * color space. If it is null, or the request cannot be met, + * the decoder will pick either the color space embedded in the image + * or the color space best suited for the requested image configuration + * (for instance {@link ColorSpace.Named#SRGB sRGB} for + * the {@link Bitmap.Config#ARGB_8888} configuration).</p> + * + * <p>{@link Bitmap.Config#RGBA_F16} always uses the + * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space). + * Bitmaps in other configurations without an embedded color space are + * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p> + * + * <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are + * currently supported. An <code>IllegalArgumentException</code> will + * be thrown by the decode methods when setting a non-RGB color space + * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p> + * + * <p class="note">The specified color space's transfer function must be + * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An + * <code>IllegalArgumentException</code> will be thrown by the decode methods + * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the + * specified color space returns null.</p> + * + * <p>After decode, the bitmap's color space is stored in + * {@link #outColorSpace}.</p> + */ + public ColorSpace inPreferredColorSpace = null; + + /** * If true (which is the default), the resulting bitmap will have its * color channels pre-multipled by the alpha channel. * @@ -403,9 +431,22 @@ public class BitmapFactory { } static void validate(Options opts) { - if (opts != null && opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) { + if (opts == null) return; + + if (opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) { throw new IllegalArgumentException("Bitmaps with Config.HARWARE are always immutable"); } + + if (opts.inPreferredColorSpace != null) { + if (!(opts.inPreferredColorSpace instanceof ColorSpace.Rgb)) { + throw new IllegalArgumentException("The destination color space must use the " + + "RGB color model"); + } + if (((ColorSpace.Rgb) opts.inPreferredColorSpace).getTransferParameters() == null) { + throw new IllegalArgumentException("The destination color space must use an " + + "ICC parametric transfer function"); + } + } } } @@ -421,7 +462,9 @@ public class BitmapFactory { * size be returned (in opts.outWidth and opts.outHeight) * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig} * is {@link android.graphics.Bitmap.Config#HARDWARE} - * and {@link BitmapFactory.Options#inMutable} is set. + * and {@link BitmapFactory.Options#inMutable} is set, 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} */ public static Bitmap decodeFile(String pathName, Options opts) { validate(opts); @@ -463,7 +506,9 @@ public class BitmapFactory { * resources, which we pass to be able to scale the bitmap accordingly. * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig} * is {@link android.graphics.Bitmap.Config#HARDWARE} - * and {@link BitmapFactory.Options#inMutable} is set. + * and {@link BitmapFactory.Options#inMutable} is set, 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} */ public static Bitmap decodeResourceStream(Resources res, TypedValue value, InputStream is, Rect pad, Options opts) { @@ -501,7 +546,9 @@ public class BitmapFactory { * size be returned (in opts.outWidth and opts.outHeight) * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig} * is {@link android.graphics.Bitmap.Config#HARDWARE} - * and {@link BitmapFactory.Options#inMutable} is set. + * and {@link BitmapFactory.Options#inMutable} is set, 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} */ public static Bitmap decodeResource(Resources res, int id, Options opts) { validate(opts); @@ -559,7 +606,9 @@ public class BitmapFactory { * size be returned (in opts.outWidth and opts.outHeight) * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig} * is {@link android.graphics.Bitmap.Config#HARDWARE} - * and {@link BitmapFactory.Options#inMutable} is set. + * and {@link BitmapFactory.Options#inMutable} is set, 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} */ public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) { if ((offset | length) < 0 || data.length < offset + length) { @@ -641,7 +690,9 @@ public class BitmapFactory { * size be returned (in opts.outWidth and opts.outHeight) * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig} * is {@link android.graphics.Bitmap.Config#HARDWARE} - * and {@link BitmapFactory.Options#inMutable} is set. + * and {@link BitmapFactory.Options#inMutable} is set, 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} * * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT}, * if {@link InputStream#markSupported is.markSupported()} returns true, @@ -720,7 +771,9 @@ public class BitmapFactory { * @return the decoded bitmap, or null * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig} * is {@link android.graphics.Bitmap.Config#HARDWARE} - * and {@link BitmapFactory.Options#inMutable} is set. + * and {@link BitmapFactory.Options#inMutable} is set, 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} */ public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) { validate(opts); diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java index 04abca1f4bd4..2da27c7dfdbf 100644 --- a/graphics/java/android/graphics/BitmapRegionDecoder.java +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -180,7 +180,9 @@ public final class BitmapRegionDecoder { * decoded. * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig} * is {@link android.graphics.Bitmap.Config#HARDWARE} - * and {@link BitmapFactory.Options#inMutable} is set. + * and {@link BitmapFactory.Options#inMutable} is set, 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} */ public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) { BitmapFactory.Options.validate(options); diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java index 218b857ce83c..8cbf921f6a34 100644 --- a/graphics/java/android/graphics/Color.java +++ b/graphics/java/android/graphics/Color.java @@ -538,7 +538,7 @@ public class Color { /** * Returns the value of the alpha component in the range \([0..1]\). * Calling this method is equivalent to - * <code>getComponent(getComponentCount())</code>. + * <code>getComponent(getComponentCount() - 1)</code>. * * @see #red() * @see #green() @@ -690,9 +690,8 @@ public class Color { * Returns the color space encoded in the specified color long. * * @param color The color long whose color space to extract - * @return A non-null color space instance. If the color long encodes - * an unknown or invalid color space, the {@link ColorSpace.Named#SRGB sRGB} - * color space is returned + * @return A non-null color space instance + * @throws IllegalArgumentException If the encoded color space is invalid or unknown * * @see #red(long) * @see #green(long) @@ -787,6 +786,7 @@ public class Color { * * @param color The color to test * @return True if the color is in the sRGB color space, false otherwise + * @throws IllegalArgumentException If the encoded color space is invalid or unknown * * @see #isInColorSpace(long, ColorSpace) * @see #isWideGamut(long) @@ -802,6 +802,7 @@ public class Color { * * @param color The color to test * @return True if the color is in a wide-gamut color space, false otherwise + * @throws IllegalArgumentException If the encoded color space is invalid or unknown * * @see #isInColorSpace(long, ColorSpace) * @see #isSrgb(long) @@ -831,6 +832,7 @@ public class Color { * a color space conversion is applied if needed. * * @return An ARGB color in the sRGB color space + * @throws IllegalArgumentException If the encoded color space is invalid or unknown */ @ColorInt public static int toArgb(@ColorLong long color) { @@ -873,6 +875,7 @@ public class Color { * * @param color The color long to create a <code>Color</code> from * @return A non-null instance of {@link Color} + * @throws IllegalArgumentException If the encoded color space is invalid or unknown */ @NonNull public static Color valueOf(@ColorLong long color) { @@ -1100,6 +1103,7 @@ public class Color { * @param color The color long to convert * @param colorSpace The destination color space * @return A color long in the destination color space + * @throws IllegalArgumentException If the encoded color space is invalid or unknown */ @ColorLong public static long convert(@ColorLong long color, @NonNull ColorSpace colorSpace) { @@ -1206,7 +1210,7 @@ public class Color { * @return A value between 0 (darkest black) and 1 (lightest white) * * @throws IllegalArgumentException If the specified color's color space - * does not use the {@link ColorSpace.Model#RGB RGB} color model + * is unknown or does not use the {@link ColorSpace.Model#RGB RGB} color model */ public static float luminance(@ColorLong long color) { ColorSpace colorSpace = colorSpace(color); diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 8f78319e8380..67504cfe323b 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1338,9 +1338,8 @@ public abstract class ColorSpace { } /** - * <p>Returns an instance of {@link ColorSpace} whose ID matches the specified - * ID. If the ID is < 0 or > {@link #MAX_ID}, calling this method is equivalent - * to calling <code>get(Named.SRGB)</code>.</p> + * <p>Returns an instance of {@link ColorSpace} whose ID matches the + * specified ID.</p> * * <p>This method always returns the same instance for a given ID.</p> * @@ -1348,11 +1347,14 @@ public abstract class ColorSpace { * * @param index An integer ID between {@link #MIN_ID} and {@link #MAX_ID} * @return A non-null {@link ColorSpace} instance + * @throws IllegalArgumentException If the ID does not match the ID of one of the + * {@link Named named color spaces} */ @NonNull static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) { if (index < 0 || index > Named.values().length) { - return get(Named.SRGB); + throw new IllegalArgumentException("Invalid ID, must be in the range [0.." + + Named.values().length + "]"); } return sNamedColorSpaces[index]; } diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 56f9cc71f782..97d3e5ee5609 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -1135,6 +1135,7 @@ public class Typeface { // Treat as system error since reaching here means that a system pre-installed font // can't be used by our font stack. Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage()); + return null; } return fontFamily; } @@ -1160,7 +1161,10 @@ public class Typeface { for (int i = 0; i < fontConfig.getFamilies().length; i++) { FontConfig.Family f = fontConfig.getFamilies()[i]; if (i == 0 || f.getName() == null) { - familyList.add(makeFamilyFromParsed(f, bufferForPath)); + FontFamily family = makeFamilyFromParsed(f, bufferForPath); + if (family != null) { + familyList.add(family); + } } } sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]); @@ -1177,6 +1181,9 @@ public class Typeface { typeface = sDefaultTypeface; } else { FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath); + if (fontFamily == null) { + continue; + } FontFamily[] families = { fontFamily }; typeface = Typeface.createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index e628d18d8490..6cab56c1d466 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -23,12 +23,12 @@ import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.media.MediaCodecInfo.CodecCapabilities; -import android.media.MediaMetricsSet; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.view.Surface; import java.io.IOException; @@ -3188,20 +3188,19 @@ final public class MediaCodec { /** * Return Metrics data about the current codec instance. * - * @return a MediaMetricsSet containing the set of attributes and values + * @return a {@link PersistableBundle} containing the set of attributes and values * available for the media being handled by this instance of MediaCodec - * The attributes are descibed in {@link MediaMetricsSet.MediaCodec}. + * The attributes are descibed in {@link MetricsConstants}. * - * Additional vendor-specific fields may also be present in - * the return value. + * Additional vendor-specific fields may also be present in + * the return value. */ - public MediaMetricsSet getMetrics() { - Bundle bundle = native_getMetrics(); - MediaMetricsSet mSet = new MediaMetricsSet(bundle); - return mSet; + public PersistableBundle getMetrics() { + PersistableBundle bundle = native_getMetrics(); + return bundle; } - private native Bundle native_getMetrics(); + private native PersistableBundle native_getMetrics(); /** * Change a video encoder's target bitrate on the fly. The value is an @@ -3660,4 +3659,80 @@ final public class MediaCodec { private final ByteBuffer mData; } } + + public final static class MetricsConstants + { + private MetricsConstants() {} + + /** + * Key to extract the codec being used + * from the {@link MediaCodec#getMetrics} return value. + * The value is a String. + */ + public static final String CODEC = "android.media.mediacodec.codec"; + + /** + * Key to extract the MIME type + * from the {@link MediaCodec#getMetrics} return value. + * The value is a String. + */ + public static final String MIME_TYPE = "android.media.mediacodec.mime"; + + /** + * Key to extract what the codec mode + * from the {@link MediaCodec#getMetrics} return value. + * The value is a String. Values will be one of the constants + * {@link #MODE_AUDIO} or {@link #MODE_VIDEO}. + */ + public static final String MODE = "android.media.mediacodec.mode"; + + /** + * The value returned for the key {@link #MODE} when the + * codec is a audio codec. + */ + public static final String MODE_AUDIO = "audio"; + + /** + * The value returned for the key {@link #MODE} when the + * codec is a video codec. + */ + public static final String MODE_VIDEO = "video"; + + /** + * Key to extract the flag indicating whether the codec is running + * as an encoder or decoder from the {@link MediaCodec#getMetrics} return value. + * The value is an integer. + * A 0 indicates decoder; 1 indicates encoder. + */ + public static final String ENCODER = "android.media.mediacodec.encoder"; + + /** + * Key to extract the flag indicating whether the codec is running + * in secure (DRM) mode from the {@link MediaCodec#getMetrics} return value. + * The value is an integer. + */ + public static final String SECURE = "android.media.mediacodec.secure"; + + /** + * Key to extract the width (in pixels) of the video track + * from the {@link MediaCodec#getMetrics} return value. + * The value is an integer. + */ + public static final String WIDTH = "android.media.mediacodec.width"; + + /** + * Key to extract the height (in pixels) of the video track + * from the {@link MediaCodec#getMetrics} return value. + * The value is an integer. + */ + public static final String HEIGHT = "android.media.mediacodec.height"; + + /** + * Key to extract the rotation (in degrees) to properly orient the video + * from the {@link MediaCodec#getMetrics} return. + * The value is a integer. + */ + public static final String ROTATION = "android.media.mediacodec.rotation"; + + } } diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java index a0a6a1e7ead2..fe461be6dea5 100644 --- a/media/java/android/media/MediaExtractor.java +++ b/media/java/android/media/MediaExtractor.java @@ -25,10 +25,10 @@ import android.content.res.AssetFileDescriptor; import android.media.MediaCodec; import android.media.MediaFormat; import android.media.MediaHTTPService; -import android.media.MediaMetricsSet; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; +import android.os.PersistableBundle; import com.android.internal.util.Preconditions; @@ -689,22 +689,21 @@ final public class MediaExtractor { /** * Return Metrics data about the current media container. * - * @return a MediaMetricsSet containing the set of attributes and values + * @return a {@link PersistableBundle} containing the set of attributes and values * available for the media container being handled by this instance * of MediaExtractor. - * The attributes are descibed in {@link MediaMetricsSet.MediaExtractor}. + * The attributes are descibed in {@link MetricsConstants}. * * Additional vendor-specific fields may also be present in * the return value. */ - public MediaMetricsSet getMetrics() { - Bundle bundle = native_getMetrics(); - MediaMetricsSet mSet = new MediaMetricsSet(bundle); - return mSet; + public PersistableBundle getMetrics() { + PersistableBundle bundle = native_getMetrics(); + return bundle; } - private native Bundle native_getMetrics(); + private native PersistableBundle native_getMetrics(); private static native final void native_init(); private native final void native_setup(); @@ -718,4 +717,32 @@ final public class MediaExtractor { private MediaCas mMediaCas; private long mNativeContext; + + public final static class MetricsConstants + { + private MetricsConstants() {} + + /** + * Key to extract the container format + * from the {@link MediaExtractor#getMetrics} return value. + * The value is a String. + */ + public static final String FORMAT = "android.media.mediaextractor.fmt"; + + /** + * Key to extract the container MIME type + * from the {@link MediaExtractor#getMetrics} return value. + * The value is a String. + */ + public static final String MIME_TYPE = "android.media.mediaextractor.mime"; + + /** + * Key to extract the number of tracks in the container + * from the {@link MediaExtractor#getMetrics} return value. + * The value is an integer. + */ + public static final String TRACKS = "android.media.mediaextractor.ntrk"; + + } + } diff --git a/media/java/android/media/MediaMetricsSet.java b/media/java/android/media/MediaMetricsSet.java deleted file mode 100644 index 5ecbee2127fc..000000000000 --- a/media/java/android/media/MediaMetricsSet.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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.media; - -import android.os.Bundle; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.Runnable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; -import java.net.HttpCookie; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.URL; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.BitSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; -import java.util.Set; -import java.util.UUID; -import java.util.Vector; - - -/** - * MediaMetricsSet contains the results returned by the getMetrics() - * methods defined in other Media classes such as - * {@link MediaCodec}, {@link MediaExtractor}, {@link MediaPlayer}, - * and {@link MediaRecorder}. - * - * MediaMetricsSet behaves similarly to a {@link Bundle}. It contains - * a set of keys and values. - * Methods such as {@link #getInt} and {@link #getString} are provided - * to extract values of the corresponding types. - * The {@link #keySet} method can be used to discover all of the keys - * that are present in the particular instance. - * - */ -public final class MediaMetricsSet -{ - - /** - * This MediaCodec class holds the constants defining keys related to - * the metrics for a MediaCodec. - */ - public final static class MediaCodec - { - private MediaCodec() {} - - /** - * Key to extract the codec being used - * from the {@link MediaCodec#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_CODEC = "android.media.mediacodec.codec"; - - /** - * Key to extract the MIME type - * from the {@link MediaCodec#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_MIME = "android.media.mediacodec.mime"; - - /** - * Key to extract what the codec mode - * from the {@link MediaCodec#getMetrics} return value. - * The value is a String. Values will be one of the constants - * MODE_AUDIO or MODE_VIDEO. - */ - public static final String KEY_MODE = "android.media.mediacodec.mode"; - - /** - * The value returned for the key {@link #KEY_MODE} when the - * codec is a audio codec. - */ - public static final String MODE_AUDIO = "audio"; - - /** - * The value returned for the key {@link #KEY_MODE} when the - * codec is a video codec. - */ - public static final String MODE_VIDEO = "video"; - - /** - * Key to extract the flag indicating whether the codec is running - * as an encoder or decoder from the {@link MediaCodec#getMetrics} return value. - * The value is an integer. - * A 0 indicates decoder; 1 indicates encoder. - */ - public static final String KEY_ENCODER = "android.media.mediacodec.encoder"; - - /** - * Key to extract the flag indicating whether the codec is running - * in secure (DRM) mode from the {@link MediaCodec#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_SECURE = "android.media.mediacodec.secure"; - - /** - * Key to extract the width (in pixels) of the video track - * from the {@link MediaCodec#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_WIDTH = "android.media.mediacodec.width"; - - /** - * Key to extract the height (in pixels) of the video track - * from the {@link MediaCodec#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_HEIGHT = "android.media.mediacodec.height"; - - /** - * Key to extract the rotation (in degrees) to properly orient the video - * from the {@link MediaCodec#getMetrics} return. - * The value is a integer. - */ - public static final String KEY_ROTATION = "android.media.mediacodec.rotation"; - - } - - /** - * This class holds the constants defining keys related to - * the metrics for a MediaExtractor. - */ - public final static class MediaExtractor - { - private MediaExtractor() {} - - /** - * Key to extract the container format - * from the {@link MediaExtractor#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_FORMAT = "android.media.mediaextractor.fmt"; - - /** - * Key to extract the container MIME type - * from the {@link MediaExtractor#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_MIME = "android.media.mediaextractor.mime"; - - /** - * Key to extract the number of tracks in the container - * from the {@link MediaExtractor#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_TRACKS = "android.media.mediaextractor.ntrk"; - - } - - /** - * This class holds the constants defining keys related to - * the metrics for a MediaPlayer. - */ - public final static class MediaPlayer - { - private MediaPlayer() {} - - /** - * Key to extract the MIME type of the video track - * from the {@link MediaPlayer#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_MIME_VIDEO = "android.media.mediaplayer.video.mime"; - - /** - * Key to extract the codec being used to decode the video track - * from the {@link MediaPlayer#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_CODEC_VIDEO = "android.media.mediaplayer.video.codec"; - - /** - * Key to extract the width (in pixels) of the video track - * from the {@link MediaPlayer#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_WIDTH = "android.media.mediaplayer.width"; - - /** - * Key to extract the height (in pixels) of the video track - * from the {@link MediaPlayer#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_HEIGHT = "android.media.mediaplayer.height"; - - /** - * Key to extract the count of video frames played - * from the {@link MediaPlayer#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_FRAMES = "android.media.mediaplayer.frames"; - - /** - * Key to extract the count of video frames dropped - * from the {@link MediaPlayer#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_FRAMES_DROPPED = "android.media.mediaplayer.dropped"; - - /** - * Key to extract the MIME type of the audio track - * from the {@link MediaPlayer#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_MIME_AUDIO = "android.media.mediaplayer.audio.mime"; - - /** - * Key to extract the codec being used to decode the audio track - * from the {@link MediaPlayer#getMetrics} return value. - * The value is a String. - */ - public static final String KEY_CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; - - /** - * Key to extract the duration (in milliseconds) of the - * media being played - * from the {@link MediaPlayer#getMetrics} return value. - * The value is a long. - */ - public static final String KEY_DURATION = "android.media.mediaplayer.durationMs"; - - /** - * Key to extract the playing time (in milliseconds) of the - * media being played - * from the {@link MediaPlayer#getMetrics} return value. - * The value is a long. - */ - public static final String KEY_PLAYING = "android.media.mediaplayer.playingMs"; - - /** - * Key to extract the count of errors encountered while - * playing the media - * from the {@link MediaPlayer#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_ERRORS = "android.media.mediaplayer.err"; - - /** - * Key to extract an (optional) error code detected while - * playing the media - * from the {@link MediaPlayer#getMetrics} return value. - * The value is an integer. - */ - public static final String KEY_ERROR_CODE = "android.media.mediaplayer.errcode"; - - } - - /** - * This class holds the constants defining keys related to - * the metrics for a MediaRecorder. - */ - public final static class MediaRecorder - { - private MediaRecorder() {} - - /** - * Key to extract the audio bitrate - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; - - /** - * Key to extract the number of audio channels - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; - - /** - * Key to extract the audio samplerate - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; - - /** - * Key to extract the audio timescale - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; - - /** - * Key to extract the video capture frame rate - * from the {@link MediaRecorder#getMetrics} return. - * The value is a double. - */ - public static final String KEY_CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; - - /** - * Key to extract the video capture framerate enable value - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; - - /** - * Key to extract the intended playback frame rate - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_FRAMERATE = "android.media.mediarecorder.frame-rate"; - - /** - * Key to extract the height (in pixels) of the captured video - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_HEIGHT = "android.media.mediarecorder.height"; - - /** - * Key to extract the recorded movies time units - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - * A value of 1000 indicates that the movie's timing is in milliseconds. - */ - public static final String KEY_MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; - - /** - * Key to extract the rotation (in degrees) to properly orient the video - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_ROTATION = "android.media.mediarecorder.rotation"; - - /** - * Key to extract the video bitrate from being used - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; - - /** - * Key to extract the value for how often video iframes are generated - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; - - /** - * Key to extract the video encoding level - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; - - /** - * Key to extract the video encoding profile - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; - - /** - * Key to extract the recorded video time units - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - * A value of 1000 indicates that the video's timing is in milliseconds. - */ - public static final String KEY_VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; - - /** - * Key to extract the width (in pixels) of the captured video - * from the {@link MediaRecorder#getMetrics} return. - * The value is an integer. - */ - public static final String KEY_WIDTH = "android.media.mediarecorder.width"; - - } - - /* - * Methods that we want - */ - - private Bundle mBundle; - - MediaMetricsSet(Bundle bundle) { - mBundle = bundle; - } - - /** - * Returns the number of mappings contained in this Bundle. - * - * @return the number of mappings as an int. - */ - public int size() { - return mBundle.size(); - } - - /** - * Returns true if the mapping of this MediaMetricsSet is empty, - * false otherwise. - */ - public boolean isEmpty() { - return mBundle.isEmpty(); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a double value - */ - public double getDouble(String key, double defaultValue) { - return mBundle.getDouble(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return an int value - */ - public int getInt(String key, int defaultValue) { - return mBundle.getInt(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a long value - */ - public long getLong(String key, long defaultValue) { - return mBundle.getLong(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key or if a null - * value is explicitly associated with the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist or if a null - * value is associated with the given key. - * @return the String value associated with the given key, or defaultValue - * if no valid String object is currently mapped to that key. - */ - public String getString(String key, String defaultValue) { - return mBundle.getString(key, defaultValue); - } - - /** - * Returns a Set containing the Strings used as keys in this Bundle. - * - * @return a Set of String keys - */ - public Set<String> keySet() { - return mBundle.keySet(); - } - - - - public String toString() { - return mBundle.toString(); - } - -} - diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 71a968b4d4b5..9386246bd128 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -33,6 +33,7 @@ import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; +import android.os.PersistableBundle; import android.os.Process; import android.os.PowerManager; import android.os.SystemProperties; @@ -48,7 +49,6 @@ import android.graphics.SurfaceTexture; import android.media.AudioManager; import android.media.MediaDrm; import android.media.MediaFormat; -import android.media.MediaMetricsSet; import android.media.MediaTimeProvider; import android.media.PlaybackParams; import android.media.SubtitleController; @@ -1491,20 +1491,19 @@ public class MediaPlayer extends PlayerBase /** * Return Metrics data about the current player. * - * @return a MediaMetricsSet containing the set of attributes and values + * @return a {@link PersistableBundle} containing the set of attributes and values * available for the media being handled by this instance of MediaPlayer - * The attributes are descibed in {@link MediaMetricsSet.MediaPlayer}. + * The attributes are descibed in {@link MetricsConstants}. * * Additional vendor-specific fields may also be present in * the return value. */ - public MediaMetricsSet getMetrics() { - Bundle bundle = native_getMetrics(); - MediaMetricsSet mSet = new MediaMetricsSet(bundle); - return mSet; + public PersistableBundle getMetrics() { + PersistableBundle bundle = native_getMetrics(); + return bundle; } - private native Bundle native_getMetrics(); + private native PersistableBundle native_getMetrics(); /** * Checks whether the MediaPlayer is playing. @@ -5418,4 +5417,98 @@ public class MediaPlayer extends PlayerBase } } } + + public final static class MetricsConstants + { + private MetricsConstants() {} + + /** + * Key to extract the MIME type of the video track + * from the {@link MediaPlayer#getMetrics} return value. + * The value is a String. + */ + public static final String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime"; + + /** + * Key to extract the codec being used to decode the video track + * from the {@link MediaPlayer#getMetrics} return value. + * The value is a String. + */ + public static final String CODEC_VIDEO = "android.media.mediaplayer.video.codec"; + + /** + * Key to extract the width (in pixels) of the video track + * from the {@link MediaPlayer#getMetrics} return value. + * The value is an integer. + */ + public static final String WIDTH = "android.media.mediaplayer.width"; + + /** + * Key to extract the height (in pixels) of the video track + * from the {@link MediaPlayer#getMetrics} return value. + * The value is an integer. + */ + public static final String HEIGHT = "android.media.mediaplayer.height"; + + /** + * Key to extract the count of video frames played + * from the {@link MediaPlayer#getMetrics} return value. + * The value is an integer. + */ + public static final String FRAMES = "android.media.mediaplayer.frames"; + + /** + * Key to extract the count of video frames dropped + * from the {@link MediaPlayer#getMetrics} return value. + * The value is an integer. + */ + public static final String FRAMES_DROPPED = "android.media.mediaplayer.dropped"; + + /** + * Key to extract the MIME type of the audio track + * from the {@link MediaPlayer#getMetrics} return value. + * The value is a String. + */ + public static final String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime"; + + /** + * Key to extract the codec being used to decode the audio track + * from the {@link MediaPlayer#getMetrics} return value. + * The value is a String. + */ + public static final String CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; + + /** + * Key to extract the duration (in milliseconds) of the + * media being played + * from the {@link MediaPlayer#getMetrics} return value. + * The value is a long. + */ + public static final String DURATION = "android.media.mediaplayer.durationMs"; + + /** + * Key to extract the playing time (in milliseconds) of the + * media being played + * from the {@link MediaPlayer#getMetrics} return value. + * The value is a long. + */ + public static final String PLAYING = "android.media.mediaplayer.playingMs"; + + /** + * Key to extract the count of errors encountered while + * playing the media + * from the {@link MediaPlayer#getMetrics} return value. + * The value is an integer. + */ + public static final String ERRORS = "android.media.mediaplayer.err"; + + /** + * Key to extract an (optional) error code detected while + * playing the media + * from the {@link MediaPlayer#getMetrics} return value. + * The value is an integer. + */ + public static final String ERROR_CODE = "android.media.mediaplayer.errcode"; + + } } diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 4675e327ce25..858c6783eb1d 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -20,11 +20,11 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.ActivityThread; import android.hardware.Camera; -import android.media.MediaMetricsSet; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.util.Log; import android.view.Surface; @@ -1267,23 +1267,142 @@ public class MediaRecorder /** * Return Metrics data about the current Mediarecorder instance. * - * @return a MediaMetricsSet containing the set of attributes and values + * @return a {@link PersistableBundle} containing the set of attributes and values * available for the media being generated by this instance of * MediaRecorder. - * The attributes are descibed in {@link MediaMetricsSet.MediaRecorder}. + * The attributes are descibed in {@link MetricsConstants}. * * Additional vendor-specific fields may also be present in * the return value. */ - public MediaMetricsSet getMetrics() { - Bundle bundle = native_getMetrics(); - MediaMetricsSet mSet = new MediaMetricsSet(bundle); - return mSet; + public PersistableBundle getMetrics() { + PersistableBundle bundle = native_getMetrics(); + return bundle; } - private native Bundle native_getMetrics(); + private native PersistableBundle native_getMetrics(); @Override protected void finalize() { native_finalize(); } + + public final static class MetricsConstants + { + private MetricsConstants() {} + + /** + * Key to extract the audio bitrate + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate"; + + /** + * Key to extract the number of audio channels + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels"; + + /** + * Key to extract the audio samplerate + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate"; + + /** + * Key to extract the audio timescale + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale"; + + /** + * Key to extract the video capture frame rate + * from the {@link MediaRecorder#getMetrics} return. + * The value is a double. + */ + public static final String CAPTURE_FPS = "android.media.mediarecorder.capture-fps"; + + /** + * Key to extract the video capture framerate enable value + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable"; + + /** + * Key to extract the intended playback frame rate + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String FRAMERATE = "android.media.mediarecorder.frame-rate"; + + /** + * Key to extract the height (in pixels) of the captured video + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String HEIGHT = "android.media.mediarecorder.height"; + + /** + * Key to extract the recorded movies time units + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + * A value of 1000 indicates that the movie's timing is in milliseconds. + */ + public static final String MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale"; + + /** + * Key to extract the rotation (in degrees) to properly orient the video + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String ROTATION = "android.media.mediarecorder.rotation"; + + /** + * Key to extract the video bitrate from being used + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate"; + + /** + * Key to extract the value for how often video iframes are generated + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval"; + + /** + * Key to extract the video encoding level + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level"; + + /** + * Key to extract the video encoding profile + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile"; + + /** + * Key to extract the recorded video time units + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + * A value of 1000 indicates that the video's timing is in milliseconds. + */ + public static final String VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale"; + + /** + * Key to extract the width (in pixels) of the captured video + * from the {@link MediaRecorder#getMetrics} return. + * The value is an integer. + */ + public static final String WIDTH = "android.media.mediarecorder.width"; + + } } diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index a8dd3133b275..2178607152c6 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -2002,7 +2002,7 @@ static const JNINativeMethod gMethods[] = { { "getName", "()Ljava/lang/String;", (void *)android_media_MediaCodec_getName }, - { "native_getMetrics", "()Landroid/os/Bundle;", + { "native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaCodec_native_getMetrics}, { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index c2cfed9bfa2f..9e5d3d12f0bd 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -905,7 +905,7 @@ static const JNINativeMethod gMethods[] = { { "hasCacheReachedEndOfStream", "()Z", (void *)android_media_MediaExtractor_hasCacheReachedEOS }, - {"native_getMetrics", "()Landroid/os/Bundle;", + {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaExtractor_native_getMetrics}, }; diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp index fb606bac7828..8979cec2e864 100644 --- a/media/jni/android_media_MediaMetricsJNI.cpp +++ b/media/jni/android_media_MediaMetricsJNI.cpp @@ -24,15 +24,12 @@ namespace android { -// place the attributes into a java Bundle object -// decide whether this is appropriately scoped here. -// if we do it somewhere else, we have to figure a "give me all the attrs" -// access to the inside of MediaAnalyticsItem +// place the attributes into a java PersistableBundle object jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle) { - jclass clazzBundle = env->FindClass("android/os/Bundle"); + jclass clazzBundle = env->FindClass("android/os/PersistableBundle"); if (clazzBundle==NULL) { - ALOGD("can't find android/os/Bundle"); + ALOGD("can't find android/os/PersistableBundle"); return NULL; } // sometimes the caller provides one for us to fill @@ -58,7 +55,7 @@ jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *i // -- get name, get type, get value // -- insert appropriately into the bundle for (size_t i = 0 ; i < item->mPropCount; i++ ) { - MediaAnalyticsItem::Prop *prop = &item->mProps[i]; + MediaAnalyticsItem::Prop *prop = &item->mProps[i]; // build the key parameter from prop->mName jstring keyName = env->NewStringUTF(prop->mName); // invoke the appropriate method to insert diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 1b52cf58cbff..2fc4afd28335 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -1393,7 +1393,7 @@ static const JNINativeMethod gMethods[] = { {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, - {"native_getMetrics", "()Landroid/os/Bundle;", (void *)android_media_MediaPlayer_native_getMetrics}, + {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer_native_getMetrics}, {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams}, {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams}, {"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams}, diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 7a63e003875a..2c1e834187e8 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -688,7 +688,7 @@ static const JNINativeMethod gMethods[] = { {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize}, {"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface }, - {"native_getMetrics", "()Landroid/os/Bundle;", (void *)android_media_MediaRecorder_native_getMetrics}, + {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaRecorder_native_getMetrics}, }; // This function only registers the native methods, and is called from diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java index 444705cfc79f..ece700dc8b6d 100644 --- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java +++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java @@ -100,8 +100,8 @@ public final class BluetoothMidiDevice { int newState) { String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) { - Log.i(TAG, "Connected to GATT server."); - Log.i(TAG, "Attempting to start service discovery:" + + Log.d(TAG, "Connected to GATT server."); + Log.d(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { Log.i(TAG, "Disconnected from GATT server."); @@ -112,24 +112,24 @@ public final class BluetoothMidiDevice { @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { - List<BluetoothGattService> services = mBluetoothGatt.getServices(); - for (BluetoothGattService service : services) { - if (MIDI_SERVICE.equals(service.getUuid())) { - Log.d(TAG, "found MIDI_SERVICE"); - List<BluetoothGattCharacteristic> characteristics - = service.getCharacteristics(); - for (BluetoothGattCharacteristic characteristic : characteristics) { - if (MIDI_CHARACTERISTIC.equals(characteristic.getUuid())) { - Log.d(TAG, "found MIDI_CHARACTERISTIC"); - mCharacteristic = characteristic; - - // Specification says to read the characteristic first and then - // switch to receiving notifications - mBluetoothGatt.readCharacteristic(characteristic); - break; - } - } - break; + BluetoothGattService service = gatt.getService(MIDI_SERVICE); + if (service != null) { + Log.d(TAG, "found MIDI_SERVICE"); + BluetoothGattCharacteristic characteristic + = service.getCharacteristic(MIDI_CHARACTERISTIC); + if (characteristic != null) { + Log.d(TAG, "found MIDI_CHARACTERISTIC"); + mCharacteristic = characteristic; + + // Request a lower Connection Interval for better latency. + boolean result = gatt.requestConnectionPriority( + BluetoothGatt.CONNECTION_PRIORITY_HIGH); + Log.d(TAG, "requestConnectionPriority(CONNECTION_PRIORITY_HIGH):" + + result); + + // Specification says to read the characteristic first and then + // switch to receiving notifications + mBluetoothGatt.readCharacteristic(characteristic); } } } else { diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java index 76a64e51b9e1..b145290d0ce6 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java @@ -34,6 +34,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.android.companiondevicemanager.DeviceDiscoveryService.DeviceFilterPair; +import com.android.internal.util.Preconditions; public class DeviceChooserActivity extends Activity { @@ -78,22 +79,35 @@ public class DeviceChooserActivity extends Activity { } mPairButton = findViewById(R.id.button_pair); - mPairButton.setOnClickListener((view) -> - onPairTapped(getService().mSelectedDevice)); + mPairButton.setOnClickListener(v -> onPairTapped(getService().mSelectedDevice)); updatePairButtonEnabled(); mCancelButton = findViewById(R.id.button_cancel); - mCancelButton.setOnClickListener((view) -> { - setResult(RESULT_CANCELED); - finish(); - }); + mCancelButton.setOnClickListener(v -> cancel()); + } + + private void cancel() { + getService().onCancel(); + setResult(RESULT_CANCELED); + finish(); + } + + @Override + protected void onPause() { + super.onPause(); + if (!isFinishing()) { + cancel(); + } } private CharSequence getCallingAppName() { try { final PackageManager packageManager = getPackageManager(); + String callingPackage = Preconditions.checkStringNotEmpty( + getCallingPackage(), + "This activity must be called for result"); return packageManager.getApplicationLabel( - packageManager.getApplicationInfo(getCallingPackage(), 0)); + packageManager.getApplicationInfo(callingPackage, 0)); } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException(e); } diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index 1b6aca1ba65e..246bd2bc7ce0 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -110,6 +110,11 @@ public class DeviceDiscoveryService extends Service { private final ScanCallback mBLEScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { + if (DEBUG) { + Log.i(LOG_TAG, + "BLE.onScanResult(callbackType = " + callbackType + ", result = " + result + + ")"); + } final DeviceFilterPair<ScanResult> deviceFilterPair = DeviceFilterPair.findMatch(result, mBLEFilters); if (deviceFilterPair == null) return; @@ -126,6 +131,10 @@ public class DeviceDiscoveryService extends Service { private BroadcastReceiver mBluetoothDeviceFoundBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + if (DEBUG) { + Log.i(LOG_TAG, + "BL.onReceive(context = " + context + ", intent = " + intent + ")"); + } final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); final DeviceFilterPair<BluetoothDevice> deviceFilterPair = DeviceFilterPair.findMatch(device, mBluetoothFilters); @@ -191,7 +200,8 @@ public class DeviceDiscoveryService extends Service { mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter); reset(); - } + } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request); + if (!ArrayUtils.isEmpty(mDevicesFound)) { onReadyToShowUI(); } @@ -221,6 +231,7 @@ public class DeviceDiscoveryService extends Service { } private void reset() { + if (DEBUG) Log.i(LOG_TAG, "reset()"); mDevicesFound.clear(); mSelectedDevice = null; mDevicesAdapter.notifyDataSetChanged(); @@ -294,6 +305,14 @@ public class DeviceDiscoveryService extends Service { } } + void onCancel() { + try { + mServiceCallback.onDeviceSelectionCancel(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + class DevicesAdapter extends ArrayAdapter<DeviceFilterPair> { //TODO wifi icon private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth); @@ -369,8 +388,15 @@ public class DeviceDiscoveryService extends Service { public static <T extends Parcelable> DeviceFilterPair<T> findMatch( T dev, @Nullable List<? extends DeviceFilter<T>> filters) { if (isEmpty(filters)) return new DeviceFilterPair<>(dev, null); - final DeviceFilter<T> matchingFilter = CollectionUtils.find(filters, (f) -> f.matches(dev)); - return matchingFilter != null ? new DeviceFilterPair<>(dev, matchingFilter) : null; + final DeviceFilter<T> matchingFilter + = CollectionUtils.find(filters, f -> f.matches(dev)); + + DeviceFilterPair<T> result = matchingFilter != null + ? new DeviceFilterPair<>(dev, matchingFilter) + : null; + if (DEBUG) Log.i(LOG_TAG, "findMatch(dev = " + dev + ", filters = " + filters + + ") -> " + result); + return result; } public String getDisplayName() { diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml index 55d000c14ad1..e399fb170759 100644 --- a/packages/DefaultContainerService/AndroidManifest.xml +++ b/packages/DefaultContainerService/AndroidManifest.xml @@ -1,5 +1,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.defcontainer" coreApp="true"> + <uses-permission android:name="android.permission.ALLOCATE_AGGRESSIVE"/> <uses-permission android:name="android.permission.ASEC_ACCESS"/> <uses-permission android:name="android.permission.ASEC_CREATE"/> <uses-permission android:name="android.permission.ASEC_DESTROY"/> diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 37a68e0c557a..934787774637 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -30,6 +30,7 @@ import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.res.ObbInfo; import android.content.res.ObbScanner; +import android.os.Binder; import android.os.Environment; import android.os.Environment.UserEnvironment; import android.os.FileUtils; @@ -179,6 +180,15 @@ public class DefaultContainerService extends IntentService { return ret; } + final int recommendedInstallLocation; + final long token = Binder.clearCallingIdentity(); + try { + recommendedInstallLocation = PackageHelper.resolveInstallLocation(context, + pkg.packageName, pkg.installLocation, sizeBytes, flags); + } finally { + Binder.restoreCallingIdentity(token); + } + ret.packageName = pkg.packageName; ret.splitNames = pkg.splitNames; ret.versionCode = pkg.versionCode; @@ -186,8 +196,7 @@ public class DefaultContainerService extends IntentService { ret.splitRevisionCodes = pkg.splitRevisionCodes; ret.installLocation = pkg.installLocation; ret.verifiers = pkg.verifiers; - ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context, - pkg.packageName, pkg.installLocation, sizeBytes, flags); + ret.recommendedInstallLocation = recommendedInstallLocation; ret.multiArch = pkg.multiArch; return ret; diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml deleted file mode 100644 index e055de77ebe5..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml +++ /dev/null @@ -1,32 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillAlpha="0.3" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml deleted file mode 100644 index 8a488170e438..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml +++ /dev/null @@ -1,32 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillAlpha="0.3" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml deleted file mode 100644 index 39cc94cad4db..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml +++ /dev/null @@ -1,32 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillAlpha="0.3" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml deleted file mode 100644 index 012e95e985ce..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="32.0dp" - android:height="32.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="#FFFFFF"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml b/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml deleted file mode 100644 index 96e2fd4e5f82..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml +++ /dev/null @@ -1,36 +0,0 @@ -<!-- - Copyright (C) 2015 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="32dp" - android:height="32dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:name="dot1" - android:fillColor="#FFFFFFFF" - android:pathData="M9.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/> - <path - android:name="dot2" - android:fillColor="#4DFFFFFF" - android:pathData="M14.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/> - <path - android:name="dot3" - android:fillColor="#4DFFFFFF" - android:pathData="M19.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/> - <path - android:fillColor="#4DFFFFFF" - android:pathData="M2.0,22.0l6.0,0.0 0.0,-4.0 14.0,0.0 0.0,-16.0z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change_animation.xml b/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change_animation.xml deleted file mode 100644 index 2186aa82e83f..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change_animation.xml +++ /dev/null @@ -1,27 +0,0 @@ -<!-- - Copyright (C) 2015 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. ---> -<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" - android:drawable="@drawable/ic_qs_signal_carrier_network_change" > - <target - android:name="dot1" - android:animation="@anim/ic_qs_signal_blink_1"/> - <target - android:name="dot2" - android:animation="@anim/ic_qs_signal_blink_2"/> - <target - android:name="dot3" - android:animation="@anim/ic_qs_signal_blink_3"/> -</animated-vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml deleted file mode 100644 index 326373ddc9e8..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml +++ /dev/null @@ -1,25 +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:autoMirrored="true" - android:width="32dp" - android:height="32dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#4DFFFFFF" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml deleted file mode 100644 index 8baa4ebd0c26..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml +++ /dev/null @@ -1,28 +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:autoMirrored="true" - android:width="32dp" - android:height="32dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#4DFFFFFF" - android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml deleted file mode 100644 index bf19a718e0fc..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml +++ /dev/null @@ -1,28 +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:autoMirrored="true" - android:width="32dp" - android:height="32dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#4DFFFFFF" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M14.000000,10.000000l-12.000000,12.000000 12.000000,0.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml deleted file mode 100644 index 01839e8589ef..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml +++ /dev/null @@ -1,28 +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:autoMirrored="true" - android:width="32dp" - android:height="32dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#4DFFFFFF" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M16.700001,7.300000l-14.700001,14.700000 14.700001,0.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml deleted file mode 100644 index 48151ad78a6c..000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml +++ /dev/null @@ -1,25 +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:autoMirrored="true" - android:width="32dp" - android:height="32dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml deleted file mode 100644 index 8bc872a99951..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="17.0dp" - android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillColor="?attr/backgroundColor"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="?attr/fillColor"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml deleted file mode 100644 index e267d25b43d9..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml +++ /dev/null @@ -1,25 +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:autoMirrored="true" - android:width="17dp" - android:height="17dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="?attr/backgroundColor" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml deleted file mode 100644 index 8fa7630b0fae..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="17.0dp" - android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z" - android:fillColor="?attr/fillColor"/> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillColor="?attr/backgroundColor"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="?attr/fillColor"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml deleted file mode 100644 index 60822f409aee..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml +++ /dev/null @@ -1,28 +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:autoMirrored="true" - android:width="17dp" - android:height="17dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="?attr/backgroundColor" - android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/> - <path - android:fillColor="?attr/fillColor" - android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml deleted file mode 100644 index 2a660a39d510..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="17.0dp" - android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z" - android:fillColor="?attr/fillColor"/> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillColor="?attr/backgroundColor"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="?attr/fillColor"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml deleted file mode 100644 index 5e68eeda3b24..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml +++ /dev/null @@ -1,28 +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:autoMirrored="true" - android:width="17dp" - android:height="17dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="?attr/backgroundColor" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> - <path - android:fillColor="?attr/fillColor" - android:pathData="M14.000000,10.000000l-12.000000,12.000000 12.000000,0.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml deleted file mode 100644 index 9e0a43353eea..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="17.0dp" - android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillColor="?attr/backgroundColor"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="?attr/fillColor"/> - <path - android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z" - android:fillColor="?attr/fillColor"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml deleted file mode 100644 index 599b34ae56a3..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml +++ /dev/null @@ -1,28 +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:autoMirrored="true" - android:width="17dp" - android:height="17dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="?attr/backgroundColor" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> - <path - android:fillColor="?attr/fillColor" - android:pathData="M16.700001,7.300000l-14.700001,14.700000 14.700001,0.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml deleted file mode 100644 index 01f670311750..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- - 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:autoMirrored="true" - android:width="17.0dp" - android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z" - android:fillColor="?attr/fillColor"/> - <path - android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z" - android:fillColor="?attr/fillColor"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml deleted file mode 100644 index b66d89a4c6bb..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml +++ /dev/null @@ -1,25 +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:autoMirrored="true" - android:width="17dp" - android:height="17dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="?attr/singleToneColor" - android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change.xml b/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change.xml deleted file mode 100644 index f69ffe49b138..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change.xml +++ /dev/null @@ -1,36 +0,0 @@ -<!-- - Copyright (C) 2015 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="17dp" - android:height="17dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:name="dot1" - android:fillColor="?attr/fillColor" - android:pathData="M9.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/> - <path - android:name="dot2" - android:fillColor="?attr/backgroundColor" - android:pathData="M14.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/> - <path - android:name="dot3" - android:fillColor="?attr/backgroundColor" - android:pathData="M19.0,19.0l3.0,0.0l0.0,3.0l-3.0,0.0z"/> - <path - android:fillColor="?attr/backgroundColor" - android:pathData="M2.0,22.0l6.0,0.0 0.0,-4.0 14.0,0.0 0.0,-16.0z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change_animation.xml b/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change_animation.xml deleted file mode 100644 index 275f037778c0..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_signal_carrier_network_change_animation.xml +++ /dev/null @@ -1,27 +0,0 @@ -<!-- - Copyright (C) 2015 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. ---> -<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" - android:drawable="@drawable/stat_sys_signal_carrier_network_change" > - <target - android:name="dot1" - android:animation="@anim/ic_signal_blink_1"/> - <target - android:name="dot2" - android:animation="@anim/ic_signal_blink_2"/> - <target - android:name="dot3" - android:animation="@anim/ic_signal_blink_3"/> -</animated-vector> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 6d8a07784a30..9c7a6a00a4fb 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -760,4 +760,6 @@ <dimen name="default_gear_space">18dp</dimen> <dimen name="cell_overlay_padding">18dp</dimen> + <dimen name="signal_icon_size">17dp</dimen> + </resources> diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml index 3f0caab23ab4..0c4fd23ca107 100644 --- a/packages/SystemUI/res/values/styles_tv.xml +++ b/packages/SystemUI/res/values/styles_tv.xml @@ -21,5 +21,6 @@ <style name="PipTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:backgroundDimEnabled">false</item> + <item name="android:windowDisablePreview">true</item> </style> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index f8d1bfbc18be..7a6ac571f9e0 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -165,11 +165,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private int mPhoneState; private boolean mKeyguardIsVisible; - /** - * If true, fingerprint was already authenticated and we don't need to start listening again - * until the Keyguard has been dismissed. - */ - private boolean mFingerprintAlreadyAuthenticated; private boolean mGoingToSleep; private boolean mBouncer; private boolean mBootCompleted; @@ -409,11 +404,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private void onFingerprintAuthenticated(int userId) { Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated"); mUserFingerprintAuthenticated.put(userId, true); - - // If fingerprint unlocking is allowed, this event will lead to a Keyguard dismiss or to a - // wake-up (if Keyguard is not showing), so we don't need to listen until Keyguard is - // fully gone. - mFingerprintAlreadyAuthenticated = isUnlockingWithFingerprintAllowed(); + // Don't send cancel if authentication succeeds + mFingerprintCancelSignal = null; for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -922,7 +914,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } mGoingToSleep = true; - mFingerprintAlreadyAuthenticated = false; updateFingerprintListeningState(); } @@ -1092,8 +1083,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private boolean shouldListenForFingerprint() { return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer || mGoingToSleep) - && !mSwitchingUser && !mFingerprintAlreadyAuthenticated - && !isFingerprintDisabled(getCurrentUser()); + && !mSwitchingUser && !isFingerprintDisabled(getCurrentUser()); } private void startListeningForFingerprint() { @@ -1416,9 +1406,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { cb.onKeyguardVisibilityChangedRaw(showing); } } - if (!showing) { - mFingerprintAlreadyAuthenticated = false; - } updateFingerprintListeningState(); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index f3fb1efb7dec..ec56e15dbd8d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -33,6 +33,8 @@ public interface DozeHost { boolean isPulsingBlocked(); void startPendingIntentDismissingKeyguard(PendingIntent intent); + void abortPulsing(); + void extendPulse(); interface Callback { default void onNotificationHeadsUp() {} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index f27521e20bbc..1cc5fb956c99 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -58,12 +58,15 @@ public class DozeMachine { /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */ DOZE_PULSE_DONE, /** Doze is done. DozeService is finished. */ - FINISH; + FINISH, + /** AOD, but the display is temporarily off. */ + DOZE_AOD_PAUSED; boolean canPulse() { switch (this) { case DOZE: case DOZE_AOD: + case DOZE_AOD_PAUSED: return true; default: return false; @@ -85,6 +88,7 @@ public class DozeMachine { case UNINITIALIZED: case INITIALIZED: case DOZE: + case DOZE_AOD_PAUSED: return Display.STATE_OFF; case DOZE_PULSING: case DOZE_AOD: @@ -241,6 +245,11 @@ public class DozeMachine { if (mState == State.FINISH) { return State.FINISH; } + if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD || mState == State.DOZE) + && requestedState == State.DOZE_PULSE_DONE) { + Log.i(TAG, "Dropping pulse done because current state is already done: " + mState); + return mState; + } if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) { Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState); return mState; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 2ac06579f259..73f522244a60 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -22,6 +22,8 @@ import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; @@ -40,6 +42,7 @@ import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; import java.util.List; +import java.util.function.Consumer; public class DozeSensors { @@ -55,18 +58,22 @@ public class DozeSensors { private final DozeParameters mDozeParameters; private final AmbientDisplayConfiguration mConfig; private final WakeLock mWakeLock; + private final Consumer<Boolean> mProxCallback; private final Callback mCallback; private final Handler mHandler = new Handler(); + private final ProxSensor mProxSensor; public DozeSensors(Context context, SensorManager sensorManager, DozeParameters dozeParameters, - AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback) { + AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback, + Consumer<Boolean> proxCallback) { mContext = context; mSensorManager = sensorManager; mDozeParameters = dozeParameters; mConfig = config; mWakeLock = wakeLock; + mProxCallback = proxCallback; mResolver = mContext.getContentResolver(); mSensors = new TriggerSensor[] { @@ -86,6 +93,8 @@ public class DozeSensors { true /* configured */, DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP) }; + + mProxSensor = new ProxSensor(); mCallback = callback; } @@ -129,6 +138,10 @@ public class DozeSensors { } } + public void setProxListening(boolean listen) { + mProxSensor.setRegistered(listen); + } + private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri, int userId) { @@ -152,6 +165,43 @@ public class DozeSensors { } } + private class ProxSensor implements SensorEventListener { + + boolean mRegistered; + Boolean mCurrentlyFar; + + void setRegistered(boolean register) { + if (mRegistered == register) { + // Send an update even if we don't re-register. + mHandler.post(() -> { + if (mCurrentlyFar != null) { + mProxCallback.accept(mCurrentlyFar); + } + }); + return; + } + if (register) { + mRegistered = mSensorManager.registerListener(this, + mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY), + SensorManager.SENSOR_DELAY_NORMAL, mHandler); + } else { + mSensorManager.unregisterListener(this); + mRegistered = false; + mCurrentlyFar = null; + } + } + + @Override + public void onSensorChanged(SensorEvent event) { + mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange(); + mProxCallback.accept(mCurrentlyFar); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + } + private class TriggerSensor extends TriggerEventListener { final Sensor mSensor; final boolean mConfigured; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 1b9bf73847b5..9b3593b9cbdd 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -46,6 +46,7 @@ import java.io.PrintWriter; public class DozeTriggers implements DozeMachine.Part { private static final String TAG = "DozeTriggers"; + private static final boolean DEBUG = DozeService.DEBUG; /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */ private static final String PULSE_ACTION = "com.android.systemui.doze.pulse"; @@ -81,7 +82,7 @@ public class DozeTriggers implements DozeMachine.Part { mWakeLock = wakeLock; mAllowPulseTriggers = allowPulseTriggers; mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, - wakeLock, this::onSensor); + wakeLock, this::onSensor, this::onProximityFar); mUiModeManager = mContext.getSystemService(UiModeManager.class); } @@ -113,6 +114,22 @@ public class DozeTriggers implements DozeMachine.Part { } } + private void onProximityFar(boolean far) { + final boolean near = !far; + DozeMachine.State state = mMachine.getState(); + if (near && state == DozeMachine.State.DOZE_PULSING) { + if (DEBUG) Log.i(TAG, "Prox NEAR, ending pulse"); + mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE); + } + if (far && state == DozeMachine.State.DOZE_AOD_PAUSED) { + if (DEBUG) Log.i(TAG, "Prox FAR, unpausing AOD"); + mMachine.requestState(DozeMachine.State.DOZE_AOD); + } else if (near && state == DozeMachine.State.DOZE_AOD) { + if (DEBUG) Log.i(TAG, "Prox NEAR, pausing AOD"); + mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSED); + } + } + private void onCarMode() { mMachine.requestState(DozeMachine.State.FINISH); } @@ -131,15 +148,21 @@ public class DozeTriggers implements DozeMachine.Part { break; case DOZE: case DOZE_AOD: + case DOZE_AOD_PAUSED: + mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE); mDozeSensors.setListening(true); if (oldState != DozeMachine.State.INITIALIZED) { mDozeSensors.reregisterAllSensors(); } break; + case DOZE_PULSING: + mDozeSensors.setProxListening(true); + break; case FINISH: mBroadcastReceiver.unregister(mContext); mDozeHost.removeCallback(mHostCallback); mDozeSensors.setListening(false); + mDozeSensors.setProxListening(false); break; default: } @@ -156,6 +179,7 @@ public class DozeTriggers implements DozeMachine.Part { private void requestPulse(final int reason, boolean performedProxCheck) { Assert.isMainThread(); + mDozeHost.extendPulse(); if (mPulsePending || !mAllowPulseTriggers || !canPulse()) { return; } @@ -286,6 +310,8 @@ public class DozeTriggers implements DozeMachine.Part { } private class TriggerReceiver extends BroadcastReceiver { + private boolean mRegistered; + @Override public void onReceive(Context context, Intent intent) { if (PULSE_ACTION.equals(intent.getAction())) { @@ -301,14 +327,22 @@ public class DozeTriggers implements DozeMachine.Part { } public void register(Context context) { + if (mRegistered) { + return; + } IntentFilter filter = new IntentFilter(PULSE_ACTION); filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); filter.addAction(Intent.ACTION_USER_SWITCHED); context.registerReceiver(this, filter); + mRegistered = true; } public void unregister(Context context) { + if (!mRegistered) { + return; + } context.unregisterReceiver(this); + mRegistered = false; } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index f577654c724c..6098a20a0c64 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -75,11 +75,14 @@ public class DozeUi implements DozeMachine.Part { scheduleTimeTick(); break; case DOZE: + case DOZE_AOD_PAUSED: unscheduleTimeTick(); break; case DOZE_REQUEST_PULSE: pulseWhileDozing(DozeLog.PULSE_REASON_NOTIFICATION /* TODO */); break; + case DOZE_PULSE_DONE: + mHost.abortPulsing(); case INITIALIZED: mHost.startDozing(); break; diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index 4b0ff145bae6..8ac97f3306be 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -35,6 +35,7 @@ import android.view.View; import com.android.settingslib.applications.InterestingConfigChanges; import com.android.systemui.Dependency; import com.android.systemui.plugins.Plugin; +import com.android.systemui.util.leak.LeakDetector; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -77,6 +78,11 @@ public class FragmentHostManager { public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) { FragmentHostManager.this.onFragmentViewDestroyed(f); } + + @Override + public void onFragmentDestroyed(FragmentManager fm, Fragment f) { + Dependency.get(LeakDetector.class).trackGarbage(f); + } }; mFragments.getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks, true); 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 9c4f16b808ab..ac0670348af2 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -195,6 +195,7 @@ public class PipMenuActivity extends Activity { updateFromIntent(getIntent()); setTitle(R.string.pip_menu_title); + setDisablePreviewScreenshots(true); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 1151c8cb4b50..92ff17a1f029 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -163,7 +163,6 @@ public class CellularTile extends QSTileImpl<SignalState> { boolean enabled; boolean wifiEnabled; boolean airplaneModeEnabled; - int mobileSignalIconId; String signalContentDescription; int dataTypeIconId; String dataContentDescription; @@ -193,7 +192,6 @@ public class CellularTile extends QSTileImpl<SignalState> { return; } mInfo.enabled = qsIcon.visible; - mInfo.mobileSignalIconId = qsIcon.icon; mInfo.signalContentDescription = qsIcon.contentDescription; mInfo.dataTypeIconId = qsType; mInfo.dataContentDescription = typeContentDescription; @@ -210,7 +208,6 @@ public class CellularTile extends QSTileImpl<SignalState> { mInfo.noSim = show; if (mInfo.noSim) { // Make sure signal gets cleared out when no sims. - mInfo.mobileSignalIconId = 0; mInfo.dataTypeIconId = 0; // Show a No SIMs description to avoid emergency calls message. mInfo.enabled = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java index 2a1e06347763..fee24b7b7645 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java @@ -306,6 +306,10 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl } private void snapBack(View animView, float velocity) { + if (mFadeAnimator != null) { + mFadeAnimator.cancel(); + } + mHandler.removeCallbacks(mCheckForDrag); mMenuSnappedTo = false; mSnapping = true; mSwipeHelper.snap(animView, 0 /* leftTarget */, velocity); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index d5f0e7c2a60b..dc254f9fdc1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -42,6 +42,7 @@ import android.widget.LinearLayout; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.statusbar.phone.SignalDrawable; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.DarkIconDispatcher; import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; @@ -192,7 +193,7 @@ public class SignalClusterView extends LinearLayout implements NetworkController mNoSimsCombo = findViewById(R.id.no_sims_combo); mWifiAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer); mWifiSignalSpacer = findViewById(R.id.wifi_signal_spacer); - mMobileSignalGroup = findViewById(R.id.mobile_signal_group); + mMobileSignalGroup = findViewById(R.id.mobile_signal_group); maybeScaleVpnAndNoSimsIcons(); } @@ -327,15 +328,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController if (hasCorrectSubs(subs)) { return; } - // Clear out all old subIds. - for (PhoneState state : mPhoneStates) { - if (state.mMobile != null) { - state.maybeStopAnimatableDrawable(state.mMobile); - } - if (state.mMobileDark != null) { - state.maybeStopAnimatableDrawable(state.mMobileDark); - } - } mPhoneStates.clear(); if (mMobileSignalGroup != null) { mMobileSignalGroup.removeAllViews(); @@ -428,16 +420,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController } for (PhoneState state : mPhoneStates) { - if (state.mMobile != null) { - state.maybeStopAnimatableDrawable(state.mMobile); - state.mMobile.setImageDrawable(null); - state.mLastMobileStrengthId = -1; - } - if (state.mMobileDark != null) { - state.maybeStopAnimatableDrawable(state.mMobileDark); - state.mMobileDark.setImageDrawable(null); - state.mLastMobileStrengthId = -1; - } if (state.mMobileType != null) { state.mMobileType.setImageDrawable(null); state.mLastMobileTypeId = -1; @@ -654,7 +636,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController private int mMobileStrengthId = 0, mMobileTypeId = 0; private int mLastMobileStrengthId = -1; private int mLastMobileTypeId = -1; - private int mLastMobileActivityId = -1; private boolean mIsMobileTypeIconWide; private String mMobileDescription, mMobileTypeDescription; @@ -681,13 +662,18 @@ public class SignalClusterView extends LinearLayout implements NetworkController mMobileRoaming = root.findViewById(R.id.mobile_roaming); mMobileActivityIn = root.findViewById(R.id.mobile_in); mMobileActivityOut = root.findViewById(R.id.mobile_out); + // TODO: Remove the 2 instances because now the drawable can handle darkness. + mMobile.setImageDrawable(new SignalDrawable(mMobile.getContext())); + SignalDrawable drawable = new SignalDrawable(mMobileDark.getContext()); + drawable.setDarkIntensity(1); + mMobileDark.setImageDrawable(drawable); } public boolean apply(boolean isSecondaryIcon) { if (mMobileVisible && !mIsAirplaneMode) { if (mLastMobileStrengthId != mMobileStrengthId) { - updateAnimatableIcon(mMobile, mMobileStrengthId); - updateAnimatableIcon(mMobileDark, mMobileStrengthId); + mMobile.getDrawable().setLevel(mMobileStrengthId); + mMobileDark.getDrawable().setLevel(mMobileStrengthId); mLastMobileStrengthId = mMobileStrengthId; } @@ -724,49 +710,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController return mMobileVisible; } - private void updateAnimatableIcon(ImageView view, int resId) { - maybeStopAnimatableDrawable(view); - setIconForView(view, resId); - maybeStartAnimatableDrawable(view); - } - - private void maybeStopAnimatableDrawable(ImageView view) { - Drawable drawable = view.getDrawable(); - - // Check if the icon has been scaled. If it has retrieve the actual drawable out of the - // wrapper. - if (drawable instanceof ScalingDrawableWrapper) { - drawable = ((ScalingDrawableWrapper) drawable).getDrawable(); - } - - if (drawable instanceof Animatable) { - Animatable ad = (Animatable) drawable; - if (ad.isRunning()) { - ad.stop(); - } - } - } - - private void maybeStartAnimatableDrawable(ImageView view) { - Drawable drawable = view.getDrawable(); - - // Check if the icon has been scaled. If it has retrieve the actual drawable out of the - // wrapper. - if (drawable instanceof ScalingDrawableWrapper) { - drawable = ((ScalingDrawableWrapper) drawable).getDrawable(); - } - - if (drawable instanceof Animatable) { - Animatable ad = (Animatable) drawable; - if (ad instanceof AnimatedVectorDrawable) { - ((AnimatedVectorDrawable) ad).forceAnimationOnUI(); - } - if (!ad.isRunning()) { - ad.start(); - } - } - } - public void populateAccessibilityEvent(AccessibilityEvent event) { if (mMobileVisible && mMobileGroup != null && mMobileGroup.getContentDescription() != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java index 67f8426586ea..677fa81a12cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java @@ -11,6 +11,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.telephony.SignalStrength; import android.util.Log; import android.util.TypedValue; import android.view.View; @@ -18,6 +19,7 @@ import android.widget.ImageView; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.ScalingDrawableWrapper; +import com.android.systemui.statusbar.phone.SignalDrawable; import com.android.systemui.statusbar.policy.BluetoothController; import static com.android.systemui.statusbar.phone.StatusBar.DEBUG; @@ -47,12 +49,12 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement * Note that the icon is the same for 0 and 1. */ private static final int[] SIGNAL_STRENGTH_ICONS = { - R.drawable.stat_sys_signal_0_fully, - R.drawable.stat_sys_signal_0_fully, - R.drawable.stat_sys_signal_1_fully, - R.drawable.stat_sys_signal_2_fully, - R.drawable.stat_sys_signal_3_fully, - R.drawable.stat_sys_signal_4_fully, + 0, + 0, + 1, + 2, + 3, + 4, }; private static final int INVALID_SIGNAL = -1; @@ -65,6 +67,7 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement private final ImageView mNetworkSignalView; private final float mIconScaleFactor; + private final SignalDrawable mSignalDrawable; private BluetoothHeadsetClient mBluetoothHeadsetClient; @@ -79,6 +82,9 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement TypedValue typedValue = new TypedValue(); context.getResources().getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true); mIconScaleFactor = typedValue.getFloat(); + mSignalDrawable = new SignalDrawable(mNetworkSignalView.getContext()); + mNetworkSignalView.setImageDrawable( + new ScalingDrawableWrapper(mSignalDrawable, mIconScaleFactor)); if (mAdapter == null) { return; @@ -187,14 +193,12 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement } } - private void setNetworkSignalIcon(int iconId) { + private void setNetworkSignalIcon(int level) { // Setting the icon on a child view of mSignalView, so toggle this container visible. mSignalsView.setVisibility(View.VISIBLE); - // Using mNetworkSignalView's context to get the Drawable in order to preserve the theme. - Drawable icon = mNetworkSignalView.getContext().getDrawable(iconId); - - mNetworkSignalView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor)); + mSignalDrawable.setLevel(SignalDrawable.getState(level, + SignalStrength.NUM_SIGNAL_STRENGTH_BINS, false)); mNetworkSignalView.setVisibility(View.VISIBLE); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index c3f8d9711b9c..40776ea92db7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -158,6 +158,10 @@ public class DozeParameters { return sPickupSubtypePerformsProxMatcher.isIn(subType); } + public int getPulseVisibleDurationExtended() { + return 2 * getPulseVisibleDuration(); + } + /** * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index b78f7482b9f3..c5f23c5e066a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -30,6 +30,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.systemui.Interpolators; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; +import com.android.systemui.doze.DozeTriggers; /** * Controller which handles all the doze animations of the scrims. @@ -43,8 +44,6 @@ public class DozeScrimController { private final ScrimController mScrimController; private final Context mContext; - private final View mStackScroller; - private final NotificationPanelView mNotificationPanelView; private boolean mDozing; private DozeHost.PulseCallback mPulseCallback; @@ -53,24 +52,22 @@ public class DozeScrimController { private Animator mBehindAnimator; private float mInFrontTarget; private float mBehindTarget; + private boolean mDozingAborted; - public DozeScrimController(ScrimController scrimController, Context context, - View stackScroller, NotificationPanelView notificationPanelView) { + public DozeScrimController(ScrimController scrimController, Context context) { mContext = context; - mStackScroller = stackScroller; mScrimController = scrimController; mDozeParameters = new DozeParameters(context); - mNotificationPanelView = notificationPanelView; } public void setDozing(boolean dozing, boolean animate) { if (mDozing == dozing) return; mDozing = dozing; if (mDozing) { + mDozingAborted = false; abortAnimations(); mScrimController.setDozeBehindAlpha(1f); mScrimController.setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? 0f : 1f); - mNotificationPanelView.setDark(true); } else { cancelPulsing(); if (animate) { @@ -85,8 +82,6 @@ public class DozeScrimController { mScrimController.setDozeBehindAlpha(0f); mScrimController.setDozeInFrontAlpha(0f); } - // TODO: animate - mNotificationPanelView.setDark(false); } } @@ -116,10 +111,19 @@ public class DozeScrimController { cancelPulsing(); if (mDozing) { mScrimController.setDozeBehindAlpha(1f); - mScrimController.setDozeInFrontAlpha(1f); + mScrimController.setDozeInFrontAlpha( + mDozeParameters.getAlwaysOn() && !mDozingAborted ? 0f : 1f); } } + /** + * Aborts dozing immediately. + */ + public void abortDoze() { + mDozingAborted = true; + abortPulsing(); + } + public void onScreenTurnedOn() { if (isPulsing()) { final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP @@ -139,12 +143,17 @@ public class DozeScrimController { return mDozing; } + public void extendPulse() { + mHandler.removeCallbacks(mPulseOut); + } + private void cancelPulsing() { if (DEBUG) Log.d(TAG, "Cancel pulsing"); if (mPulseCallback != null) { mHandler.removeCallbacks(mPulseIn); mHandler.removeCallbacks(mPulseOut); + mHandler.removeCallbacks(mPulseOutExtended); pulseFinished(); } } @@ -271,12 +280,23 @@ public class DozeScrimController { if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing); if (!mDozing) return; mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); + mHandler.postDelayed(mPulseOutExtended, + mDozeParameters.getPulseVisibleDurationExtended()); + } + }; + + private final Runnable mPulseOutExtended = new Runnable() { + @Override + public void run() { + mHandler.removeCallbacks(mPulseOut); + mPulseOut.run(); } }; private final Runnable mPulseOut = new Runnable() { @Override public void run() { + mHandler.removeCallbacks(mPulseOutExtended); if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing); if (!mDozing) return; startScrimAnimation(true /* inFront */, mDozeParameters.getAlwaysOn() ? 0 : 1, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java index 2bb3cbc31ceb..92069142a61f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java @@ -221,7 +221,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { case MODE_WAKE_AND_UNLOCK: Trace.beginSection("MODE_WAKE_AND_UNLOCK"); mStatusBarWindowManager.setStatusBarFocusable(false); - mDozeScrimController.abortPulsing(); + mDozeScrimController.abortDoze(); mKeyguardViewMediator.onWakeAndUnlocking(); mScrimController.setWakeAndUnlocking(); if (mStatusBar.getNavigationBarView() != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java new file mode 100644 index 000000000000..a9eb20ba3a57 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java @@ -0,0 +1,342 @@ +/* + * 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 com.android.systemui.statusbar.phone; + +import android.animation.ArgbEvaluator; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.Path; +import android.graphics.Path.Direction; +import android.graphics.Path.FillType; +import android.graphics.Path.Op; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.util.Log; + +import com.android.settingslib.R; +import com.android.settingslib.Utils; + +public class SignalDrawable extends Drawable { + + private static final String TAG = "SignalDrawable"; + + private static final int NUM_DOTS = 3; + + private static final float VIEWPORT = 24f; + private static final float PAD = 2f / VIEWPORT; + private static final float CUT_OUT = 7.9f / VIEWPORT; + + private static final float DOT_SIZE = 3f / VIEWPORT; + private static final float DOT_PADDING = 1f / VIEWPORT; + private static final float DOT_CUT_WIDTH = (DOT_SIZE * 3) + (DOT_PADDING * 5); + private static final float DOT_CUT_HEIGHT = (DOT_SIZE * 1) + (DOT_PADDING * 1); + + private static final float[] FIT = {2.26f, -3.02f, 1.76f}; + + // All of these are masks to push all of the drawable state into one int for easy callbacks + // and flow through sysui. + private static final int LEVEL_MASK = 0xff; + private static final int NUM_LEVEL_SHIFT = 8; + private static final int NUM_LEVEL_MASK = 0xff << NUM_LEVEL_SHIFT; + private static final int STATE_SHIFT = 16; + private static final int STATE_MASK = 0xff << STATE_SHIFT; + private static final int STATE_NONE = 0; + private static final int STATE_EMPTY = 1; + private static final int STATE_CUT = 2; + private static final int STATE_CARRIER_CHANGE = 3; + + private static final long DOT_DELAY = 1000; + + private static float[][] X_PATH = new float[][]{ + {21.9f / VIEWPORT, 17.0f / VIEWPORT}, + {-1.1f / VIEWPORT, -1.1f / VIEWPORT}, + {-1.9f / VIEWPORT, 1.9f / VIEWPORT}, + {-1.9f / VIEWPORT, -1.9f / VIEWPORT}, + {-1.1f / VIEWPORT, 1.1f / VIEWPORT}, + {1.9f / VIEWPORT, 1.9f / VIEWPORT}, + {-1.9f / VIEWPORT, 1.9f / VIEWPORT}, + {1.1f / VIEWPORT, 1.1f / VIEWPORT}, + {1.9f / VIEWPORT, -1.9f / VIEWPORT}, + {1.9f / VIEWPORT, 1.9f / VIEWPORT}, + {1.1f / VIEWPORT, -1.1f / VIEWPORT}, + {-1.9f / VIEWPORT, -1.9f / VIEWPORT}, + }; + + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final int mDarkModeBackgroundColor; + private final int mDarkModeFillColor; + private final int mLightModeBackgroundColor; + private final int mLightModeFillColor; + private final Path mFullPath = new Path(); + private final Path mForegroundPath = new Path(); + private final Path mXPath = new Path(); + private final int mIntrinsicSize; + private final Handler mHandler; + private float mOldDarkIntensity = -1; + private float mNumLevels = 1; + private int mLevel; + private int mState; + private boolean mVisible; + private boolean mAnimating; + private int mCurrentDot; + + public SignalDrawable(Context context) { + mDarkModeBackgroundColor = + Utils.getDefaultColor(context, R.color.dark_mode_icon_color_dual_tone_background); + mDarkModeFillColor = + Utils.getDefaultColor(context, R.color.dark_mode_icon_color_dual_tone_fill); + mLightModeBackgroundColor = + Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_background); + mLightModeFillColor = + Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill); + mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size); + mHandler = new Handler(); + setDarkIntensity(0); + } + + @Override + public int getIntrinsicWidth() { + return mIntrinsicSize; + } + + @Override + public int getIntrinsicHeight() { + return mIntrinsicSize; + } + + public void setNumLevels(int levels) { + if (levels == mNumLevels) return; + mNumLevels = levels; + invalidateSelf(); + } + + private void setSignalState(int state) { + if (state == mState) return; + mState = state; + updateAnimation(); + invalidateSelf(); + } + + private void updateAnimation() { + boolean shouldAnimate = (mState == STATE_CARRIER_CHANGE) && mVisible; + if (shouldAnimate == mAnimating) return; + mAnimating = shouldAnimate; + if (shouldAnimate) { + mChangeDot.run(); + } else { + mHandler.removeCallbacks(mChangeDot); + } + } + + @Override + protected boolean onLevelChange(int state) { + setNumLevels(getNumLevels(state)); + setSignalState(getState(state)); + int level = getLevel(state); + if (level != mLevel) { + mLevel = level; + invalidateSelf(); + } + return true; + } + + public void setDarkIntensity(float darkIntensity) { + if (darkIntensity == mOldDarkIntensity) { + return; + } + mPaint.setColor(getBackgroundColor(darkIntensity)); + mForegroundPaint.setColor(getFillColor(darkIntensity)); + mOldDarkIntensity = darkIntensity; + invalidateSelf(); + } + + private int getFillColor(float darkIntensity) { + return getColorForDarkIntensity( + darkIntensity, mLightModeFillColor, mDarkModeFillColor); + } + + private int getBackgroundColor(float darkIntensity) { + return getColorForDarkIntensity( + darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor); + } + + private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) { + return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + invalidateSelf(); + } + + @Override + public void draw(@NonNull Canvas canvas) { + mFullPath.reset(); + mFullPath.setFillType(FillType.WINDING); + float width = getBounds().width(); + float height = getBounds().height(); + float padding = (PAD * width); + mFullPath.moveTo(width - padding, height - padding); + mFullPath.lineTo(width - padding, padding); + mFullPath.lineTo(padding, height - padding); + mFullPath.lineTo(width - padding, height - padding); + + if (mState == STATE_CARRIER_CHANGE) { + float cutWidth = (DOT_CUT_WIDTH * width); + float cutHeight = (DOT_CUT_HEIGHT * width); + float dotSize = (DOT_SIZE * height); + float dotPadding = (DOT_PADDING * height); + + mFullPath.moveTo(width - padding, height - padding); + mFullPath.rLineTo(-cutWidth, 0); + mFullPath.rLineTo(0, -cutHeight); + mFullPath.rLineTo(cutWidth, 0); + mFullPath.rLineTo(0, cutHeight); + float dotSpacing = dotPadding * 2 + dotSize; + float x = width - padding - dotSize; + float y = height - padding - dotSize; + mForegroundPath.reset(); + drawDot(mFullPath, mForegroundPath, x, y, dotSize, 2); + drawDot(mFullPath, mForegroundPath, x - dotSpacing, y, dotSize, 1); + drawDot(mFullPath, mForegroundPath, x - dotSpacing * 2, y, dotSize, 0); + } else if (mState == STATE_CUT) { + float cut = (CUT_OUT * width); + mFullPath.moveTo(width - padding, height - padding); + mFullPath.rLineTo(-cut, 0); + mFullPath.rLineTo(0, -cut); + mFullPath.rLineTo(cut, 0); + mFullPath.rLineTo(0, cut); + } + + mPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL); + mForegroundPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL); + + if (mState != STATE_CARRIER_CHANGE) { + mForegroundPath.reset(); + int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding)); + mForegroundPath.addRect(padding, padding, padding + sigWidth, height - padding, + Direction.CW); + mForegroundPath.op(mFullPath, Op.INTERSECT); + } + + canvas.drawPath(mFullPath, mPaint); + canvas.drawPath(mForegroundPath, mForegroundPaint); + if (mState == STATE_CUT) { + mXPath.reset(); + mXPath.moveTo(X_PATH[0][0] * width, X_PATH[0][1] * height); + for (int i = 1; i < X_PATH.length; i++) { + mXPath.rLineTo(X_PATH[i][0] * width, X_PATH[i][1] * height); + } + canvas.drawPath(mXPath, mForegroundPaint); + } + } + + private void drawDot(Path fullPath, Path foregroundPath, float x, float y, float dotSize, + int i) { + Path p = (i == mCurrentDot) ? foregroundPath : fullPath; + p.addRect(x, y, x + dotSize, y + dotSize, Direction.CW); + } + + // This is a fit line based on previous values of provided in assets, but if + // you look at the a plot of this actual fit, it makes a lot of sense, what it does + // is compress the areas that are very visually easy to see changes (the middle sections) + // and spread out the sections that are hard to see (each end of the icon). + // The current fit is cubic, but pretty easy to change the way the code is written (just add + // terms to the end of FIT). + private float calcFit(float v) { + float ret = 0; + float t = v; + for (int i = 0; i < FIT.length; i++) { + ret += FIT[i] * t; + t *= v; + } + return ret; + } + + @Override + public int getAlpha() { + return mPaint.getAlpha(); + } + + @Override + public void setAlpha(@IntRange(from = 0, to = 255) int alpha) { + mPaint.setAlpha(alpha); + mForegroundPaint.setAlpha(alpha); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + mForegroundPaint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return 255; + } + + @Override + public boolean setVisible(boolean visible, boolean restart) { + mVisible = visible; + updateAnimation(); + return super.setVisible(visible, restart); + } + + private final Runnable mChangeDot = new Runnable() { + @Override + public void run() { + if (++mCurrentDot == NUM_DOTS) { + mCurrentDot = 0; + } + invalidateSelf(); + mHandler.postDelayed(mChangeDot, DOT_DELAY); + } + }; + + public static int getLevel(int fullState) { + return fullState & LEVEL_MASK; + } + + public static int getState(int fullState) { + return (fullState & STATE_MASK) >> STATE_SHIFT; + } + + public static int getNumLevels(int fullState) { + return (fullState & NUM_LEVEL_MASK) >> NUM_LEVEL_SHIFT; + } + + public static int getState(int level, int numLevels, boolean cutOut) { + return ((cutOut ? STATE_CUT : 0) << STATE_SHIFT) + | (numLevels << NUM_LEVEL_SHIFT) + | level; + } + + public static int getCarrierChangeState(int numLevels) { + return (STATE_CARRIER_CHANGE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT); + } + + public static int getEmptyState(int numLevels) { + return (STATE_EMPTY << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index d3cb6a4a8782..fbf53e396b3c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1114,8 +1114,7 @@ public class StatusBar extends SystemUI implements DemoMode, } mHeadsUpManager.addListener(mScrimController); mStackScroller.setScrimController(mScrimController); - mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller, - mNotificationPanel); + mDozeScrimController = new DozeScrimController(mScrimController, context); // Other icons mVolumeComponent = getComponent(VolumeComponent.class); @@ -4332,6 +4331,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); mScrimController.setDozing(mDozing); mKeyguardIndicationController.setDozing(mDozing); + mNotificationPanel.setDark(mDozing); // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock // for pulsing so the Keyguard fade-out animation scrim can take over. @@ -4958,6 +4958,7 @@ public class StatusBar extends SystemUI implements DemoMode, mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD || mFingerprintUnlockController.getMode() == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; + mStatusBarWindowManager.setDozing(mDozing); updateDozingState(); Trace.endSection(); } @@ -5065,6 +5066,16 @@ public class StatusBar extends SystemUI implements DemoMode, StatusBar.this.startPendingIntentDismissingKeyguard(intent); } + @Override + public void abortPulsing() { + mDozeScrimController.abortPulsing(); + } + + @Override + public void extendPulse() { + mDozeScrimController.extendPulse(); + } + } // Begin Extra BaseStatusBar methods. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index deb0070ccbc0..0326e4025a79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -118,7 +118,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; } - if (state.keyguardShowing && !state.backdropShowing) { + if (state.keyguardShowing && !state.backdropShowing && !state.dozing) { mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; } else { mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; @@ -357,6 +357,11 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D apply(mCurrentState); } + public void setDozing(boolean dozing) { + mCurrentState.dozing = dozing; + apply(mCurrentState); + } + public void setBarHeight(int barHeight) { mBarHeight = barHeight; apply(mCurrentState); @@ -404,6 +409,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D boolean remoteInputActive; boolean forcePluginOpen; + boolean dozing; private boolean isKeyguardShowingAndNotOccluded() { return keyguardShowing && !keyguardOccluded; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 1848d4ea438b..1a09d75be632 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -255,6 +255,9 @@ public class StatusBarWindowView extends FrameLayout { if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { mStackScrollLayout.closeControlsIfOutsideTouch(ev); } + if (mService.isDozing()) { + mService.mDozeScrimController.extendPulse(); + } return super.dispatchTouchEvent(ev); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 91acf0488999..67b5596e34c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -36,6 +36,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.cdma.EriInfo; import com.android.systemui.R; +import com.android.systemui.statusbar.phone.SignalDrawable; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config; @@ -233,6 +234,29 @@ public class MobileSignalController extends SignalController< mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC); } + private int getNumLevels() { + return SignalStrength.NUM_SIGNAL_STRENGTH_BINS; + } + + @Override + public int getCurrentIconId() { + if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) { + return SignalDrawable.getCarrierChangeState(getNumLevels()); + } else if (mCurrentState.connected) { + return SignalDrawable.getState(mCurrentState.level, getNumLevels(), + mCurrentState.inetCondition == 0); + } else if (mCurrentState.enabled) { + return SignalDrawable.getEmptyState(getNumLevels()); + } else { + return 0; + } + } + + @Override + public int getQsCurrentIconId() { + return getCurrentIconId(); + } + @Override public void notifyListeners(SignalCallback callback) { MobileIconGroup icons = getIcons(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index bc3eec9795f7..c21f444d0bf3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -32,6 +32,7 @@ import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; @@ -872,11 +873,11 @@ public class NetworkControllerImpl extends BroadcastReceiver if (args.containsKey("roam")) { controller.getState().roaming = "show".equals(args.getString("roam")); } - int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH; String level = args.getString("level"); if (level != null) { controller.getState().level = level.equals("null") ? -1 - : Math.min(Integer.parseInt(level), icons[0].length - 1); + : Math.min(Integer.parseInt(level), + SignalStrength.NUM_SIGNAL_STRENGTH_BINS); controller.getState().connected = controller.getState().level >= 0; } String activity = args.getString("activity"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java index 6b2361e64da0..aaa0568a72cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -20,196 +20,20 @@ import com.android.systemui.R; import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup; class TelephonyIcons { - //***** Signal strength icons - - static final int TELEPHONY_NUM_LEVELS = 5; - - //GSM/UMTS - static final int TELEPHONY_NO_NETWORK = R.drawable.stat_sys_signal_null; - - static final int[][] TELEPHONY_SIGNAL_STRENGTH = { - { R.drawable.stat_sys_signal_0, - R.drawable.stat_sys_signal_1, - R.drawable.stat_sys_signal_2, - R.drawable.stat_sys_signal_3, - R.drawable.stat_sys_signal_4 }, - { R.drawable.stat_sys_signal_0_fully, - R.drawable.stat_sys_signal_1_fully, - R.drawable.stat_sys_signal_2_fully, - R.drawable.stat_sys_signal_3_fully, - R.drawable.stat_sys_signal_4_fully } - }; - - static final int QS_TELEPHONY_NO_NETWORK = R.drawable.ic_qs_signal_no_signal; - - static final int[][] QS_TELEPHONY_SIGNAL_STRENGTH = { - { R.drawable.ic_qs_signal_0, - R.drawable.ic_qs_signal_1, - R.drawable.ic_qs_signal_2, - R.drawable.ic_qs_signal_3, - R.drawable.ic_qs_signal_4 }, - { R.drawable.ic_qs_signal_full_0, - R.drawable.ic_qs_signal_full_1, - R.drawable.ic_qs_signal_full_2, - R.drawable.ic_qs_signal_full_3, - R.drawable.ic_qs_signal_full_4 } - }; - - static final int[][] TELEPHONY_SIGNAL_STRENGTH_ROAMING = { - { R.drawable.stat_sys_signal_0, - R.drawable.stat_sys_signal_1, - R.drawable.stat_sys_signal_2, - R.drawable.stat_sys_signal_3, - R.drawable.stat_sys_signal_4 }, - { R.drawable.stat_sys_signal_0_fully, - R.drawable.stat_sys_signal_1_fully, - R.drawable.stat_sys_signal_2_fully, - R.drawable.stat_sys_signal_3_fully, - R.drawable.stat_sys_signal_4_fully } - }; - - //CarrierNetworkChange - static final int[][] TELEPHONY_CARRIER_NETWORK_CHANGE = { - { R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation }, - { R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation, - R.drawable.stat_sys_signal_carrier_network_change_animation } - }; - - static final int[][] QS_TELEPHONY_CARRIER_NETWORK_CHANGE = { - { R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation }, - { R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation, - R.drawable.ic_qs_signal_carrier_network_change_animation } - }; - //***** Data connection icons - //GSM/UMTS - static final int[][] DATA_G = { - { R.drawable.stat_sys_data_fully_connected_g, - R.drawable.stat_sys_data_fully_connected_g, - R.drawable.stat_sys_data_fully_connected_g, - R.drawable.stat_sys_data_fully_connected_g }, - { R.drawable.stat_sys_data_fully_connected_g, - R.drawable.stat_sys_data_fully_connected_g, - R.drawable.stat_sys_data_fully_connected_g, - R.drawable.stat_sys_data_fully_connected_g } - }; - static final int QS_DATA_G = R.drawable.ic_qs_signal_g; - - static final int[][] DATA_3G = { - { R.drawable.stat_sys_data_fully_connected_3g, - R.drawable.stat_sys_data_fully_connected_3g, - R.drawable.stat_sys_data_fully_connected_3g, - R.drawable.stat_sys_data_fully_connected_3g }, - { R.drawable.stat_sys_data_fully_connected_3g, - R.drawable.stat_sys_data_fully_connected_3g, - R.drawable.stat_sys_data_fully_connected_3g, - R.drawable.stat_sys_data_fully_connected_3g } - }; - static final int QS_DATA_3G = R.drawable.ic_qs_signal_3g; - - static final int[][] DATA_E = { - { R.drawable.stat_sys_data_fully_connected_e, - R.drawable.stat_sys_data_fully_connected_e, - R.drawable.stat_sys_data_fully_connected_e, - R.drawable.stat_sys_data_fully_connected_e }, - { R.drawable.stat_sys_data_fully_connected_e, - R.drawable.stat_sys_data_fully_connected_e, - R.drawable.stat_sys_data_fully_connected_e, - R.drawable.stat_sys_data_fully_connected_e } - }; - static final int QS_DATA_E = R.drawable.ic_qs_signal_e; - - //3.5G - static final int[][] DATA_H = { - { R.drawable.stat_sys_data_fully_connected_h, - R.drawable.stat_sys_data_fully_connected_h, - R.drawable.stat_sys_data_fully_connected_h, - R.drawable.stat_sys_data_fully_connected_h }, - { R.drawable.stat_sys_data_fully_connected_h, - R.drawable.stat_sys_data_fully_connected_h, - R.drawable.stat_sys_data_fully_connected_h, - R.drawable.stat_sys_data_fully_connected_h } - }; - static final int QS_DATA_H = R.drawable.ic_qs_signal_h; - - //CDMA - // Use 3G icons for EVDO data and 1x icons for 1XRTT data - static final int[][] DATA_1X = { - { R.drawable.stat_sys_data_fully_connected_1x, - R.drawable.stat_sys_data_fully_connected_1x, - R.drawable.stat_sys_data_fully_connected_1x, - R.drawable.stat_sys_data_fully_connected_1x }, - { R.drawable.stat_sys_data_fully_connected_1x, - R.drawable.stat_sys_data_fully_connected_1x, - R.drawable.stat_sys_data_fully_connected_1x, - R.drawable.stat_sys_data_fully_connected_1x } - }; - static final int QS_DATA_1X = R.drawable.ic_qs_signal_1x; - - // LTE and eHRPD - static final int[][] DATA_4G = { - { R.drawable.stat_sys_data_fully_connected_4g, - R.drawable.stat_sys_data_fully_connected_4g, - R.drawable.stat_sys_data_fully_connected_4g, - R.drawable.stat_sys_data_fully_connected_4g }, - { R.drawable.stat_sys_data_fully_connected_4g, - R.drawable.stat_sys_data_fully_connected_4g, - R.drawable.stat_sys_data_fully_connected_4g, - R.drawable.stat_sys_data_fully_connected_4g } - }; - static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g; - - static final int[][] DATA_4G_PLUS = { - { R.drawable.stat_sys_data_fully_connected_4g_plus, - R.drawable.stat_sys_data_fully_connected_4g_plus, - R.drawable.stat_sys_data_fully_connected_4g_plus, - R.drawable.stat_sys_data_fully_connected_4g_plus }, - { R.drawable.stat_sys_data_fully_connected_4g_plus, - R.drawable.stat_sys_data_fully_connected_4g_plus, - R.drawable.stat_sys_data_fully_connected_4g_plus, - R.drawable.stat_sys_data_fully_connected_4g_plus } - }; - static final int QS_DATA_4G_PLUS = R.drawable.ic_qs_signal_4g_plus; - - // LTE branded "LTE" - static final int[][] DATA_LTE = { - { R.drawable.stat_sys_data_fully_connected_lte, - R.drawable.stat_sys_data_fully_connected_lte, - R.drawable.stat_sys_data_fully_connected_lte, - R.drawable.stat_sys_data_fully_connected_lte }, - { R.drawable.stat_sys_data_fully_connected_lte, - R.drawable.stat_sys_data_fully_connected_lte, - R.drawable.stat_sys_data_fully_connected_lte, - R.drawable.stat_sys_data_fully_connected_lte } - }; - static final int QS_DATA_LTE = R.drawable.ic_qs_signal_lte; static final int QS_DATA_LTE_PLUS = R.drawable.ic_qs_signal_lte_plus; static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode; - static final int ROAMING_ICON = R.drawable.stat_sys_roaming; + static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte; static final int ICON_LTE_PLUS = R.drawable.stat_sys_data_fully_connected_lte_plus; static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g; @@ -219,29 +43,19 @@ class TelephonyIcons { static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g; static final int ICON_4G_PLUS = R.drawable.stat_sys_data_fully_connected_4g_plus; static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x; - static final int ICON_CARRIER_NETWORK_CHANGE = - R.drawable.stat_sys_signal_carrier_network_change_animation; static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled; - static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte; - static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g; - static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g; - static final int QS_ICON_4G_PLUS = R.drawable.ic_qs_signal_4g_plus; - static final int QS_ICON_1X = R.drawable.ic_qs_signal_1x; - static final int QS_ICON_CARRIER_NETWORK_CHANGE = - R.drawable.ic_qs_signal_carrier_network_change_animation; - static final int QS_ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled; static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup( "CARRIER_NETWORK_CHANGE", - TelephonyIcons.TELEPHONY_CARRIER_NETWORK_CHANGE, - TelephonyIcons.QS_TELEPHONY_CARRIER_NETWORK_CHANGE, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.ICON_CARRIER_NETWORK_CHANGE, - TelephonyIcons.QS_ICON_CARRIER_NETWORK_CHANGE, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_carrier_network_change_mode, 0, @@ -251,12 +65,12 @@ class TelephonyIcons { static final MobileIconGroup THREE_G = new MobileIconGroup( "3G", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_3g, TelephonyIcons.ICON_3G, @@ -266,36 +80,36 @@ class TelephonyIcons { static final MobileIconGroup WFC = new MobileIconGroup( "WFC", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], 0, 0, false, 0 ); static final MobileIconGroup UNKNOWN = new MobileIconGroup( "Unknown", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], 0, 0, false, 0 ); static final MobileIconGroup E = new MobileIconGroup( "E", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_edge, TelephonyIcons.ICON_E, @@ -305,12 +119,12 @@ class TelephonyIcons { static final MobileIconGroup ONE_X = new MobileIconGroup( "1X", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_cdma, TelephonyIcons.ICON_1X, @@ -320,12 +134,12 @@ class TelephonyIcons { static final MobileIconGroup G = new MobileIconGroup( "G", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_gprs, TelephonyIcons.ICON_G, @@ -335,12 +149,12 @@ class TelephonyIcons { static final MobileIconGroup H = new MobileIconGroup( "H", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_3_5g, TelephonyIcons.ICON_H, @@ -350,12 +164,12 @@ class TelephonyIcons { static final MobileIconGroup FOUR_G = new MobileIconGroup( "4G", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_4g, TelephonyIcons.ICON_4G, @@ -365,12 +179,12 @@ class TelephonyIcons { static final MobileIconGroup FOUR_G_PLUS = new MobileIconGroup( "4G+", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0,0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_4g_plus, TelephonyIcons.ICON_4G_PLUS, @@ -380,12 +194,12 @@ class TelephonyIcons { static final MobileIconGroup LTE = new MobileIconGroup( "LTE", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_lte, TelephonyIcons.ICON_LTE, @@ -395,12 +209,12 @@ class TelephonyIcons { static final MobileIconGroup LTE_PLUS = new MobileIconGroup( "LTE+", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_data_connection_lte_plus, TelephonyIcons.ICON_LTE_PLUS, @@ -410,12 +224,12 @@ class TelephonyIcons { static final MobileIconGroup DATA_DISABLED = new MobileIconGroup( "DataDisabled", - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH, + null, + null, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, 0, 0, - TelephonyIcons.TELEPHONY_NO_NETWORK, - TelephonyIcons.QS_TELEPHONY_NO_NETWORK, + 0, + 0, AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], R.string.accessibility_cell_data_off, TelephonyIcons.ICON_DATA_DISABLED, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 19b4b173c42d..505e1d8346fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -31,6 +31,7 @@ import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.telephony.cdma.EriInfo; import com.android.settingslib.net.DataUsageController; +import com.android.systemui.statusbar.phone.SignalDrawable; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; @@ -66,12 +67,10 @@ import static org.mockito.Mockito.when; public class NetworkControllerBaseTest extends SysuiTestCase { private static final String TAG = "NetworkControllerBaseTest"; protected static final int DEFAULT_LEVEL = 2; - protected static final int DEFAULT_SIGNAL_STRENGTH = - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL]; - protected static final int DEFAULT_QS_SIGNAL_STRENGTH = - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL]; + protected static final int DEFAULT_SIGNAL_STRENGTH = DEFAULT_LEVEL; + protected static final int DEFAULT_QS_SIGNAL_STRENGTH = DEFAULT_LEVEL; protected static final int DEFAULT_ICON = TelephonyIcons.ICON_3G; - protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_ICON_3G; + protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_DATA_3G; protected NetworkControllerImpl mNetworkController; protected MobileSignalController mMobileSignalController; @@ -315,8 +314,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase { typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(), anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean()); IconState iconState = iconArg.getValue(); + int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, + false); assertEquals("Visibility in, quick settings", visible, iconState.visible); - assertEquals("Signal icon in, quick settings", icon, iconState.icon); + assertEquals("Signal icon in, quick settings", state, iconState.icon); assertEquals("Data icon in, quick settings", typeIcon, (int) typeIconArg.getValue()); assertEquals("Data direction in, in quick settings", dataIn, (boolean) dataInArg.getValue()); @@ -330,6 +331,11 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon, boolean roaming) { + verifyLastMobileDataIndicators(visible, icon, typeIcon, roaming, true); + } + + protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon, + boolean roaming, boolean inet) { ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); @@ -342,7 +348,9 @@ public class NetworkControllerBaseTest extends SysuiTestCase { anyInt(), eq(roaming)); IconState iconState = iconArg.getValue(); - assertEquals("Signal icon in status bar", icon, iconState.icon); + int state = icon == -1 ? 0 + : SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, !inet); + assertEquals("Signal icon in status bar", state, iconState.icon); assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue()); assertEquals("Visibility in status bar", visible, iconState.visible); } @@ -367,13 +375,15 @@ public class NetworkControllerBaseTest extends SysuiTestCase { IconState iconState = iconArg.getValue(); + int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, + false); assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue()); - assertEquals("Signal icon in status bar", icon, iconState.icon); + assertEquals("Signal icon in status bar", state, iconState.icon); assertEquals("Visibility in status bar", visible, iconState.visible); iconState = qsIconArg.getValue(); assertEquals("Visibility in quick settings", qsVisible, iconState.visible); - assertEquals("Signal icon in quick settings", qsIcon, iconState.icon); + assertEquals("Signal icon in quick settings", state, iconState.icon); assertEquals("Data icon in quick settings", qsTypeIcon, (int) qsTypeIconArg.getValue()); assertEquals("Data direction in in quick settings", dataIn, (boolean) dataInArg.getValue()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index e47f75066dce..dfe00f95fe4d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -24,7 +24,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { public void test3gDataIcon() { setupDefaultSignal(); - verifyDataIndicators(TelephonyIcons.DATA_3G[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_3G, TelephonyIcons.QS_DATA_3G); } @@ -34,7 +34,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_GSM); - verifyDataIndicators(TelephonyIcons.DATA_G[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_G, TelephonyIcons.QS_DATA_G); } @@ -44,7 +44,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_CDMA); - verifyDataIndicators(TelephonyIcons.DATA_1X[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_1X, TelephonyIcons.QS_DATA_1X); } @@ -54,7 +54,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_EDGE); - verifyDataIndicators(TelephonyIcons.DATA_E[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_E, TelephonyIcons.QS_DATA_E); } @@ -64,7 +64,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); - verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_LTE, TelephonyIcons.QS_DATA_LTE); } @@ -74,7 +74,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_HSPA); - verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_H, TelephonyIcons.QS_DATA_H); } @@ -103,7 +103,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); - verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_4G, TelephonyIcons.QS_DATA_4G); } @@ -147,7 +147,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // the after work. mNetworkController.handleConfigurationChanged(); - verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_4G, TelephonyIcons.QS_DATA_4G); } @@ -157,13 +157,13 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); - verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_LTE, TelephonyIcons.QS_DATA_LTE); when(mServiceState.getDataNetworkType()) .thenReturn(TelephonyManager.NETWORK_TYPE_HSPA); updateServiceState(); - verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */], + verifyDataIndicators(TelephonyIcons.ICON_H, TelephonyIcons.QS_DATA_H); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 1555856c1875..1627925ae1bc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -30,6 +30,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.settingslib.net.DataUsageController; import com.android.systemui.R; +import com.android.systemui.statusbar.phone.SignalDrawable; import org.junit.Test; import org.junit.runner.RunWith; @@ -60,7 +61,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { mMockSubDefaults, mock(DeviceProvisionedController.class)); setupNetworkController(); - verifyLastMobileDataIndicators(false, 0, 0); + verifyLastMobileDataIndicators(false, -1, 0); } @Test @@ -132,45 +133,45 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { @Test public void testSignalStrength() { - for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) { + for (int testStrength = 0; + testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) { setupDefaultSignal(); setLevel(testStrength); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength], DEFAULT_ICON); + testStrength, DEFAULT_ICON); // Verify low inet number indexing. setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, true); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[0][testStrength], DEFAULT_ICON); + testStrength, DEFAULT_ICON, false, false); } } @Test public void testCdmaSignalStrength() { - for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) { + for (int testStrength = 0; + testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) { setupDefaultSignal(); setCdma(); setLevel(testStrength); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength], - TelephonyIcons.DATA_1X[1][0 /* No direction */]); + testStrength, + TelephonyIcons.ICON_1X); } } @Test public void testSignalRoaming() { - for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) { + for (int testStrength = 0; + testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) { setupDefaultSignal(); setGsmRoaming(true); setLevel(testStrength); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength], + testStrength, DEFAULT_ICON, true); } } @@ -185,8 +186,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { setLevel(testStrength); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength], - TelephonyIcons.DATA_1X[1][0 /* No direction */], true); + testStrength, + TelephonyIcons.ICON_1X, true); } } @@ -198,7 +199,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { setLevel(testStrength); verifyLastQsMobileDataIndicators(true, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][testStrength], + testStrength, DEFAULT_QS_ICON, false, false); } } @@ -212,8 +213,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { setLevel(testStrength); verifyLastQsMobileDataIndicators(true, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][testStrength], - TelephonyIcons.QS_ICON_1X, false, false); + testStrength, + TelephonyIcons.QS_DATA_1X, false, false); } } @@ -223,7 +224,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { setConnectivity(mMobileSignalController.mTransportType, false, false); setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); - verifyLastMobileDataIndicators(true, TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][2], 0); + verifyLastMobileDataIndicators(true, DEFAULT_LEVEL, 0); } // Some tests of actual NetworkController code, just internals not display stuff @@ -418,7 +419,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { updateDataActivity(TelephonyManager.DATA_ACTIVITY_IN); verifyLastQsMobileDataIndicators(true /* visible */, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */, + DEFAULT_LEVEL /* icon */, DEFAULT_QS_ICON /* typeIcon */, true /* dataIn */, false /* dataOut */); @@ -432,11 +433,10 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { updateDataActivity(TelephonyManager.DATA_ACTIVITY_OUT); verifyLastQsMobileDataIndicators(true /* visible */, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */, + DEFAULT_LEVEL /* icon */, DEFAULT_QS_ICON /* typeIcon */, false /* dataIn */, true /* dataOut */); - } @Test @@ -446,7 +446,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { updateDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT); verifyLastQsMobileDataIndicators(true /* visible */, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */, + DEFAULT_LEVEL /* icon */, DEFAULT_QS_ICON /* typeIcon */, true /* dataIn */, true /* dataOut */); @@ -460,7 +460,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { updateDataActivity(TelephonyManager.DATA_ACTIVITY_NONE); verifyLastQsMobileDataIndicators(true /* visible */, - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */, + DEFAULT_LEVEL /* icon */, DEFAULT_QS_ICON /* typeIcon */, false /* dataIn */, false /* dataOut */); @@ -476,7 +476,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Verify baseline verifyLastMobileDataIndicators(true /* visible */, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */, + strength /* strengthIcon */, DEFAULT_ICON /* typeIcon */); // API call is made @@ -484,7 +484,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Carrier network change is true, show special indicator verifyLastMobileDataIndicators(true /* visible */, - TelephonyIcons.TELEPHONY_CARRIER_NETWORK_CHANGE[0][0] /* strengthIcon */, + SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), 0 /* typeIcon */); // Revert back @@ -492,7 +492,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Verify back in previous state verifyLastMobileDataIndicators(true /* visible */, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */, + strength /* strengthIcon */, DEFAULT_ICON /* typeIcon */); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 483a8371b85b..73fa5aa180bf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -218,7 +218,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true); setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false); verifyLastMobileDataIndicators(true, - TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL], + DEFAULT_LEVEL, 0, true); } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 63bf373316e1..57ef6d01a96b 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -48,6 +48,7 @@ import android.os.UserManager; import android.provider.Settings; import android.service.autofill.AutofillService; import android.service.autofill.AutofillServiceInfo; +import android.service.autofill.FillRequest; import android.service.autofill.IAutoFillService; import android.text.TextUtils; import android.util.LocalLog; @@ -169,7 +170,8 @@ final class AutofillManagerServiceImpl { structure.sanitizeForParceling(true); // TODO(b/33197203): Need to pipe the bundle - session.mRemoteFillService.onFillRequest(structure, null, session.mFlags); + FillRequest request = new FillRequest(structure, null, session.mFlags); + session.mRemoteFillService.onFillRequest(request); } }; diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index dd520ac43a80..3badcfcb61cd 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -20,12 +20,10 @@ import static com.android.server.autofill.Helper.DEBUG; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.assist.AssistStructure; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.os.Bundle; import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.ICancellationSignal; @@ -33,10 +31,12 @@ import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.service.autofill.AutofillService; +import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; import android.service.autofill.IFillCallback; import android.service.autofill.ISaveCallback; +import android.service.autofill.SaveRequest; import android.text.format.DateUtils; import android.util.Slog; @@ -88,7 +88,7 @@ final class RemoteFillService implements DeathRecipient { public interface FillServiceCallbacks { void onFillRequestSuccess(@Nullable FillResponse response, - @NonNull String servicePackageName); + @NonNull String servicePackageName, int requestId); void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); void onSaveRequestSuccess(@NonNull String servicePackageName); @@ -134,17 +134,16 @@ final class RemoteFillService implements DeathRecipient { mCallbacks.onServiceDied(this); } - public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle extras, - int flags) { + public void onFillRequest(@NonNull FillRequest request) { cancelScheduledUnbind(); - final PendingFillRequest request = new PendingFillRequest(structure, extras, this, flags); - mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget(); + final PendingFillRequest pendingRequest = new PendingFillRequest(request, this); + mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, pendingRequest).sendToTarget(); } - public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) { + public void onSaveRequest(@NonNull SaveRequest request) { cancelScheduledUnbind(); - final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this); - mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget(); + final PendingSaveRequest pendingRequest = new PendingSaveRequest(request, this); + mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, pendingRequest).sendToTarget(); } // Note: we are dumping without a lock held so this is a bit racy but @@ -253,10 +252,11 @@ final class RemoteFillService implements DeathRecipient { } private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest, - FillResponse response) { + FillResponse response, int requestId) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName()); + mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName(), + requestId); } }); } @@ -392,18 +392,13 @@ final class RemoteFillService implements DeathRecipient { private static final class PendingFillRequest extends PendingRequest { private final Object mLock = new Object(); private final WeakReference<RemoteFillService> mWeakService; - private final AssistStructure mStructure; - private final Bundle mExtras; + private final FillRequest mRequest; private final IFillCallback mCallback; private ICancellationSignal mCancellation; private boolean mCancelled; - private int mFlags; - public PendingFillRequest(AssistStructure structure, - Bundle extras, RemoteFillService service, int flags) { - mStructure = structure; - mExtras = extras; - mFlags = flags; + public PendingFillRequest(FillRequest request, RemoteFillService service) { + mRequest = request; mWeakService = new WeakReference<>(service); mCallback = new IFillCallback.Stub() { @Override @@ -425,11 +420,11 @@ final class RemoteFillService implements DeathRecipient { } @Override - public void onSuccess(FillResponse response) { + public void onSuccess(FillResponse response, int requestId) { RemoteFillService remoteService = mWeakService.get(); if (remoteService != null) { remoteService.dispatchOnFillRequestSuccess( - PendingFillRequest.this, response); + PendingFillRequest.this, response, requestId); } } @@ -449,8 +444,7 @@ final class RemoteFillService implements DeathRecipient { RemoteFillService remoteService = mWeakService.get(); if (remoteService != null) { try { - remoteService.mAutoFillService.onFillRequest(mStructure, - mExtras, mCallback, mFlags); + remoteService.mAutoFillService.onFillRequest(mRequest, mCallback); } catch (RemoteException e) { Slog.e(LOG_TAG, "Error calling on fill request", e); cancel(); @@ -481,14 +475,12 @@ final class RemoteFillService implements DeathRecipient { private static final class PendingSaveRequest extends PendingRequest { private final WeakReference<RemoteFillService> mWeakService; - private final AssistStructure mStructure; - private final Bundle mExtras; + private final SaveRequest mRequest; private final ISaveCallback mCallback; - public PendingSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras, + public PendingSaveRequest(@NonNull SaveRequest request, @NonNull RemoteFillService service) { - mStructure = structure; - mExtras = extras; + mRequest = request; mWeakService = new WeakReference<>(service); mCallback = new ISaveCallback.Stub() { @Override @@ -516,7 +508,7 @@ final class RemoteFillService implements DeathRecipient { final RemoteFillService service = mWeakService.get(); if (service != null) { try { - service.mAutoFillService.onSaveRequest(mStructure, mExtras, mCallback); + service.mAutoFillService.onSaveRequest(mRequest, mCallback); } catch (RemoteException e) { Slog.e(LOG_TAG, "Error calling on save request", e); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 0b1381ebec89..5feb81db4a0b 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -44,11 +44,15 @@ import android.os.Parcelable; import android.os.RemoteException; import android.service.autofill.AutofillService; import android.service.autofill.Dataset; +import android.service.autofill.FillContext; +import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; import android.service.autofill.SaveInfo; +import android.service.autofill.SaveRequest; import android.util.ArrayMap; import android.util.DebugUtils; import android.util.Slog; +import android.util.SparseArray; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; @@ -125,7 +129,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState RemoteFillService mRemoteFillService; @GuardedBy("mLock") - private ArrayList<FillResponse> mResponses; + private SparseArray<FillResponse> mResponses; /** * Response that requires a service authentitcation request. @@ -156,7 +160,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState * and used on subsequent {@code onFillRequest()} and {@code onSaveRequest()} calls. */ @GuardedBy("mLock") - private Bundle mExtras; + private Bundle mClientState; /** * Flags used to start the session. @@ -222,7 +226,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // FillServiceCallbacks @Override public void onFillRequestSuccess(@Nullable FillResponse response, - @NonNull String servicePackageName) { + @NonNull String servicePackageName, int requestId) { if (response == null) { if ((mFlags & FLAG_MANUAL_REQUEST) != 0) { getUiForShowing().showError(R.string.autofill_error_cannot_autofill); @@ -243,7 +247,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // TODO(b/33197203 , b/35707731): make sure it's ignored if there is one already mResponseWaitingAuth = response; } - processResponseLocked(response); + processResponseLocked(response, requestId); } final LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST)) @@ -343,9 +347,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (id.equals(mCurrentViewId)) { try { final ViewState view = mViewStates.get(id); - mClient.requestShowFillUi(mWindowToken, id, width, height, - view.getVirtualBounds(), - presenter); + mClient.requestShowFillUi(this.id, mWindowToken, id, width, height, + view.getVirtualBounds(), presenter); } catch (RemoteException e) { Slog.e(TAG, "Error requesting to show fill UI", e); } @@ -363,7 +366,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState public void requestHideFillUi(AutofillId id) { synchronized (mLock) { try { - mClient.requestHideFillUi(mWindowToken, id); + mClient.requestHideFillUi(this.id, mWindowToken, id); } catch (RemoteException e) { Slog.e(TAG, "Error requesting to hide fill UI", e); } @@ -395,12 +398,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState AutofillManager.EXTRA_AUTHENTICATION_RESULT); if (result instanceof FillResponse) { mMetricsLogger.action(MetricsEvent.AUTOFILL_AUTHENTICATED, mPackageName); + final int requestIndex = mResponses.indexOfValue(mResponseWaitingAuth); mResponseWaitingAuth = null; - processResponseLocked((FillResponse) result); + if (requestIndex >= 0) { + final int requestId = mResponses.keyAt(requestIndex); + processResponseLocked((FillResponse) result, requestId); + } else { + Slog.e(TAG, "Error cannot find id for auth response"); + } } else if (result instanceof Dataset) { final Dataset dataset = (Dataset) result; for (int i = 0; i < mResponses.size(); i++) { - final FillResponse response = mResponses.get(i); + final FillResponse response = mResponses.valueAt(i); final int index = response.getDatasets().indexOf(mDatasetWaitingAuth); if (index >= 0) { response.getDatasets().set(index, dataset); @@ -441,12 +450,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return true; } - final FillResponse response = mResponses.get(mResponses.size() - 1); + final int lastResponseIdx = getLastResponseIndex(); + if (lastResponseIdx < 0) { + Slog.d(TAG, "showSaveLocked(): mResponses=" + mResponses + + ", mViewStates=" + mViewStates); + return true; + } + final FillResponse response = mResponses.valueAt(lastResponseIdx); final SaveInfo saveInfo = response.getSaveInfo(); if (DEBUG) { - Slog.d(TAG, - "showSaveLocked(): mResponses=" + mResponses + ", mViewStates=" + mViewStates); + Slog.d(TAG, "showSaveLocked(): mResponses=" + mResponses + + ", mViewStates=" + mViewStates); } /* @@ -573,7 +588,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mStructure.dump(); } - mRemoteFillService.onSaveRequest(mStructure, mExtras); + // TODO(b/33197203): Implement partitioning properly + final int lastResponseIdx = getLastResponseIndex(); + final int requestId = mResponses.keyAt(lastResponseIdx); + final FillContext fillContext = new FillContext(requestId, mStructure); + final ArrayList fillContexts = new ArrayList(1); + fillContexts.add(fillContext); + + final SaveRequest saveRequest = new SaveRequest(fillContexts, mClientState); + mRemoteFillService.onSaveRequest(saveRequest); } void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int flags) { @@ -687,7 +710,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState overlay.focused = id.equals(viewState.id); node.setAutofillOverlay(overlay); } - mRemoteFillService.onFillRequest(mStructure, mExtras, 0); + + FillRequest request = new FillRequest(mStructure, mClientState, 0); + mRemoteFillService.onFillRequest(request); return newViewState; } @@ -716,7 +741,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } if (!mHasCallback) return; try { - mClient.notifyNoFillUi(mWindowToken, mCurrentViewId); + mClient.notifyNoFillUi(id, mWindowToken, mCurrentViewId); } catch (RemoteException e) { Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken + " id=" + mCurrentViewId, e); @@ -724,17 +749,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } - private void processResponseLocked(FillResponse response) { + private void processResponseLocked(FillResponse response, int requestId) { if (DEBUG) { Slog.d(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response); } if (mResponses == null) { - mResponses = new ArrayList<>(4); + mResponses = new SparseArray<>(4); } - mResponses.add(response); + mResponses.put(requestId, response); if (response != null) { - mExtras = response.getExtras(); + mClientState = response.getClientState(); } setViewStatesLocked(response, ViewState.STATE_FILLABLE); @@ -852,7 +877,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private void startAuthentication(IntentSender intent, Intent fillInIntent) { try { synchronized (mLock) { - mClient.authenticate(intent, fillInIntent); + mClient.authenticate(id, intent, fillInIntent); } } catch (RemoteException e) { Slog.e(TAG, "Error launching auth intent", e); @@ -885,7 +910,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback); - pw.print(prefix); pw.print("mExtras: "); pw.println(Helper.bundleToString(mExtras)); + pw.print(prefix); pw.print("mClientState: "); pw.println( + Helper.bundleToString(mClientState)); mRemoteFillService.dump(prefix, pw); } @@ -895,7 +921,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (DEBUG) { Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset); } - mClient.autofill(mWindowToken, dataset.getFieldIds(), dataset.getFieldValues()); + mClient.autofill(id, mWindowToken, dataset.getFieldIds(), dataset.getFieldValues()); setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED); } catch (RemoteException e) { Slog.w(TAG, "Error autofilling activity: " + e); @@ -962,4 +988,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState destroyLocked(); mService.removeSessionLocked(id); } + + private int getLastResponseIndex() { + // The response ids are monotonically increasing so + // we just find the largest id which is the last. We + // do not rely on the internal ordering in sparse + // array to avoid - wow this stopped working!? + int lastResponseIdx = -1; + int lastResponseId = -1; + final int responseCount = mResponses.size(); + for (int i = 0; i < responseCount; i++) { + if (mResponses.keyAt(i) > lastResponseId) { + lastResponseIdx = i; + } + } + return lastResponseIdx; + } } diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index 4449da92b19c..ab6a3a7cd78b 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -161,7 +161,8 @@ public final class AutoFillUI { log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL); hideFillUiUiThread(); if (mCallback != null) { - mCallback.authenticate(response.getAuthentication(), response.getExtras()); + mCallback.authenticate(response.getAuthentication(), + response.getClientState()); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 50c0a124fb8a..45b03849f228 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -55,6 +55,7 @@ import android.net.LinkProperties.CompareResult; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; +import android.net.MatchAllNetworkSpecifier; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -4044,11 +4045,8 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalArgumentException("Bad timeout specified"); } - if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER - .equals(networkCapabilities.getNetworkSpecifier())) { - throw new IllegalArgumentException("Invalid network specifier - must not be '" - + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'"); - } + MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier( + networkCapabilities.getNetworkSpecifier()); NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId(), type); @@ -4117,6 +4115,9 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceMeteredApnPolicy(networkCapabilities); ensureRequestableCapabilities(networkCapabilities); + MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier( + networkCapabilities.getNetworkSpecifier()); + NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.REQUEST); NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation); @@ -4178,6 +4179,9 @@ public class ConnectivityService extends IConnectivityManager.Stub nc.addCapability(NET_CAPABILITY_FOREGROUND); } + MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier( + networkCapabilities.getNetworkSpecifier()); + NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder); @@ -4195,6 +4199,9 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); } + MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier( + networkCapabilities.getNetworkSpecifier()); + NetworkRequest networkRequest = new NetworkRequest( new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2be53136bb74..6b0a73b25e71 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -23885,6 +23885,15 @@ public class ActivityManagerService extends IActivityManager.Stub } } + @Override + public long getActivityStartInitiatedTime(IBinder token) { + final ActivityRecord r = ActivityRecord.forTokenLocked(token); + if (r != null) { + return r.mStartInitiatedTimeMs; + } + return 0; + } + void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) { final PackageManagerInternal packageManager = getPackageManagerInternalLocked(); final boolean updateFrameworkRes = packagesToUpdate.contains("android"); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 276b267edb5b..17c7dde11726 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -341,6 +341,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo private final Rect mBounds = new Rect(); /** + * Denotes the timestamp at which this activity start was last initiated in the + * {@link SystemClock#uptimeMillis()} time base. + */ + long mStartInitiatedTimeMs; + + /** * Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)} */ private final Configuration mTmpConfig1 = new Configuration(); @@ -498,6 +504,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo pw.print(" forceNewConfig="); pw.println(forceNewConfig); pw.print(prefix); pw.print("mActivityType="); pw.println(activityTypeToString(mActivityType)); + pw.print(prefix); pw.print("mStartInitiatedTimeMs="); + TimeUtils.formatDuration(mStartInitiatedTimeMs, now, pw); if (requestedVrComponent != null) { pw.print(prefix); pw.print("requestedVrComponent="); diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 56594d3fdf48..8f1c20330e53 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -244,6 +244,7 @@ class ActivityStarter { ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container, TaskRecord inTask) { + final long activityStartTime = SystemClock.uptimeMillis(); int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; @@ -478,6 +479,7 @@ class ActivityStarter { callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null, mSupervisor, container, options, sourceRecord); + r.mStartInitiatedTimeMs = activityStartTime; if (outActivity != null) { outActivity[0] = r; } @@ -1029,6 +1031,7 @@ class ActivityStarter { // so make sure the task now has the identity of the new intent. top.getTask().setIntent(mStartActivity); } + top.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs; ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask()); top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); @@ -1052,6 +1055,7 @@ class ActivityStarter { setTaskFromIntentActivity(reusedActivity); if (!mAddingToTask && mReuseTask == null) { + reusedActivity.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs; // We didn't do anything... but it was needed (a.k.a., client don't use that // intent!) And for paranoia, make sure we have correctly resumed the top activity. resumeTargetStackIfNeeded(); @@ -1084,6 +1088,7 @@ class ActivityStarter { || mLaunchSingleTop || mLaunchSingleTask); if (dontStart) { ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask()); + top.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs; // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; if (mDoResume) { @@ -1664,6 +1669,7 @@ class ActivityStarter { // desires. if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop) && intentActivity.realActivity.equals(mStartActivity.realActivity)) { + intentActivity.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs; ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, intentActivity.getTask()); if (intentActivity.frontOfTask) { diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java index 552f0d1f8b17..fe498135feba 100644 --- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -36,6 +36,7 @@ public abstract class AuthenticationClient extends ClientMonitor { public abstract boolean handleFailedAttempt(); public abstract void resetFailedAttempts(); + private boolean mAlreadyCancelled; public AuthenticationClient(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId, @@ -129,6 +130,10 @@ public abstract class AuthenticationClient extends ClientMonitor { @Override public int stop(boolean initiatedByClient) { + if (mAlreadyCancelled) { + Slog.w(TAG, "stopAuthentication: already cancelled!"); + return 0; + } IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopAuthentication: no fingerprint HAL!"); @@ -145,6 +150,7 @@ public abstract class AuthenticationClient extends ClientMonitor { Slog.e(TAG, "stopAuthentication failed", e); return ERROR_ESRCH; } + mAlreadyCancelled = true; return 0; // success } diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index a0d0d777637f..d01de3c9157d 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -1271,8 +1271,7 @@ public final class JobSchedulerService extends com.android.server.SystemService if (job.hasIdleConstraint()) { idleCount++; } - if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint() - || job.hasNotRoamingConstraint()) { + if (job.hasConnectivityConstraint()) { connectivityCount++; } if (job.hasChargingConstraint()) { diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index fcc082790892..2e6cd3febd2d 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -368,13 +368,16 @@ public class JobStore { */ private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException { out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS); - if (jobStatus.hasConnectivityConstraint()) { + if (jobStatus.needsAnyConnectivity()) { out.attribute(null, "connectivity", Boolean.toString(true)); } - if (jobStatus.hasUnmeteredConstraint()) { + if (jobStatus.needsMeteredConnectivity()) { + out.attribute(null, "metered", Boolean.toString(true)); + } + if (jobStatus.needsUnmeteredConnectivity()) { out.attribute(null, "unmetered", Boolean.toString(true)); } - if (jobStatus.hasNotRoamingConstraint()) { + if (jobStatus.needsNonRoamingConnectivity()) { out.attribute(null, "not-roaming", Boolean.toString(true)); } if (jobStatus.hasIdleConstraint()) { @@ -713,6 +716,10 @@ public class JobStore { if (val != null) { jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); } + val = parser.getAttributeValue(null, "metered"); + if (val != null) { + jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED); + } val = parser.getAttributeValue(null, "unmetered"); if (val != null) { jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index b458d8b72ade..5ebcc93cda09 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -84,8 +84,7 @@ public class ConnectivityController extends StateController implements @Override public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { - if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint() - || jobStatus.hasNotRoamingConstraint()) { + if (jobStatus.hasConnectivityConstraint()) { updateConstraintsSatisfied(jobStatus, null); mTrackedJobs.add(jobStatus); } @@ -94,8 +93,7 @@ public class ConnectivityController extends StateController implements @Override public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { - if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint() - || jobStatus.hasNotRoamingConstraint()) { + if (jobStatus.hasConnectivityConstraint()) { mTrackedJobs.remove(jobStatus); } } @@ -114,11 +112,13 @@ public class ConnectivityController extends StateController implements && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); final boolean connected = info != null && info.isConnected(); final boolean connectionUsable = connected && validated; + final boolean metered = connected && info.isMetered(); final boolean unmetered = connected && !info.isMetered(); final boolean notRoaming = connected && !info.isRoaming(); boolean changed = false; changed |= jobStatus.setConnectivityConstraintSatisfied(connectionUsable); + changed |= jobStatus.setMeteredConstraintSatisfied(metered); changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered); changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming); @@ -134,6 +134,7 @@ public class ConnectivityController extends StateController implements + " for " + jobStatus + ": usable=" + connectionUsable + " connected=" + connected + " validated=" + validated + + " metered=" + metered + " unmetered=" + unmetered + " notRoaming=" + notRoaming); } @@ -244,9 +245,10 @@ public class ConnectivityController extends StateController implements js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); - pw.print(": C="); pw.print(js.hasConnectivityConstraint()); - pw.print(": UM="); pw.print(js.hasUnmeteredConstraint()); - pw.print(": NR="); pw.println(js.hasNotRoamingConstraint()); + pw.print(": C="); pw.print(js.needsAnyConnectivity()); + pw.print(": M="); pw.print(js.needsMeteredConnectivity()); + pw.print(": UM="); pw.print(js.needsUnmeteredConnectivity()); + pw.print(": NR="); pw.println(js.needsNonRoamingConnectivity()); } } } diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 4cdce5f52f8f..e8cc078b7eb1 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -68,6 +68,11 @@ public final class JobStatus { static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26; static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25; static final int CONSTRAINT_NOT_ROAMING = 1<<24; + static final int CONSTRAINT_METERED = 1<<23; + + static final int CONNECTIVITY_MASK = + CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY | + CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED; // Soft override: ignore constraints like time that don't affect API availability public static final int OVERRIDE_SOFT = 1; @@ -191,15 +196,28 @@ public final class JobStatus { this.numFailures = numFailures; int requiredConstraints = job.getConstraintFlags(); - if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) { - requiredConstraints |= CONSTRAINT_CONNECTIVITY; - } - if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) { - requiredConstraints |= CONSTRAINT_UNMETERED; - } - if (job.getNetworkType() == JobInfo.NETWORK_TYPE_NOT_ROAMING) { - requiredConstraints |= CONSTRAINT_NOT_ROAMING; + + switch (job.getNetworkType()) { + case JobInfo.NETWORK_TYPE_NONE: + // No constraint. + break; + case JobInfo.NETWORK_TYPE_ANY: + requiredConstraints |= CONSTRAINT_CONNECTIVITY; + break; + case JobInfo.NETWORK_TYPE_UNMETERED: + requiredConstraints |= CONSTRAINT_UNMETERED; + break; + case JobInfo.NETWORK_TYPE_NOT_ROAMING: + requiredConstraints |= CONSTRAINT_NOT_ROAMING; + break; + case JobInfo.NETWORK_TYPE_METERED: + requiredConstraints |= CONSTRAINT_METERED; + break; + default: + Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType()); + break; } + if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) { requiredConstraints |= CONSTRAINT_TIMING_DELAY; } @@ -467,15 +485,24 @@ public final class JobStatus { return job.getFlags(); } + /** Does this job have any sort of networking constraint? */ public boolean hasConnectivityConstraint() { + return (requiredConstraints&CONNECTIVITY_MASK) != 0; + } + + public boolean needsAnyConnectivity() { return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0; } - public boolean hasUnmeteredConstraint() { + public boolean needsUnmeteredConnectivity() { return (requiredConstraints&CONSTRAINT_UNMETERED) != 0; } - public boolean hasNotRoamingConstraint() { + public boolean needsMeteredConnectivity() { + return (requiredConstraints&CONSTRAINT_METERED) != 0; + } + + public boolean needsNonRoamingConnectivity() { return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0; } @@ -571,6 +598,10 @@ public final class JobStatus { return setConstraintSatisfied(CONSTRAINT_UNMETERED, state); } + boolean setMeteredConstraintSatisfied(boolean state) { + return setConstraintSatisfied(CONSTRAINT_METERED, state); + } + boolean setNotRoamingConstraintSatisfied(boolean state) { return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state); } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 44dc61de0ea9..221b2bb0886a 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -232,7 +232,9 @@ public class RankingHelper implements RankingConfig { private Record getRecord(String pkg, int uid) { final String key = recordKey(pkg, uid); - return mRecords.get(key); + synchronized (mRecords) { + return mRecords.get(key); + } } private Record getOrCreateRecord(String pkg, int uid) { @@ -243,29 +245,32 @@ public class RankingHelper implements RankingConfig { private Record getOrCreateRecord(String pkg, int uid, int importance, int priority, int visibility, boolean showBadge) { final String key = recordKey(pkg, uid); - Record r = (uid == Record.UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg) : mRecords.get(key); - if (r == null) { - r = new Record(); - r.pkg = pkg; - r.uid = uid; - r.importance = importance; - r.priority = priority; - r.visibility = visibility; - r.showBadge = showBadge; + synchronized (mRecords) { + Record r = (uid == Record.UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg) : mRecords.get( + key); + if (r == null) { + r = new Record(); + r.pkg = pkg; + r.uid = uid; + r.importance = importance; + r.priority = priority; + r.visibility = visibility; + r.showBadge = showBadge; - try { - createDefaultChannelIfNeeded(r); - } catch (NameNotFoundException e) { - Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e); - } + try { + createDefaultChannelIfNeeded(r); + } catch (NameNotFoundException e) { + Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e); + } - if (r.uid == Record.UNKNOWN_UID) { - mRestoredWithoutUids.put(pkg, r); - } else { - mRecords.put(key, r); + if (r.uid == Record.UNKNOWN_UID) { + mRestoredWithoutUids.put(pkg, r); + } else { + mRecords.put(key, r); + } } + return r; } - return r; } private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException { @@ -346,46 +351,48 @@ public class RankingHelper implements RankingConfig { out.startTag(null, TAG_RANKING); out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION)); - final int N = mRecords.size(); - for (int i = 0; i < N; i++) { - final Record r = mRecords.valueAt(i); - //TODO: http://b/22388012 - if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) { - continue; - } - final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE - || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY - || r.showBadge != DEFAULT_SHOW_BADGE || r.channels.size() > 0 - || r.groups.size() > 0; - if (hasNonDefaultSettings) { - out.startTag(null, TAG_PACKAGE); - out.attribute(null, ATT_NAME, r.pkg); - if (r.importance != DEFAULT_IMPORTANCE) { - out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance)); - } - if (r.priority != DEFAULT_PRIORITY) { - out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority)); - } - if (r.visibility != DEFAULT_VISIBILITY) { - out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility)); + synchronized (mRecords) { + final int N = mRecords.size(); + for (int i = 0; i < N; i++) { + final Record r = mRecords.valueAt(i); + //TODO: http://b/22388012 + if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) { + continue; } - out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge)); + final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE + || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY + || r.showBadge != DEFAULT_SHOW_BADGE || r.channels.size() > 0 + || r.groups.size() > 0; + if (hasNonDefaultSettings) { + out.startTag(null, TAG_PACKAGE); + out.attribute(null, ATT_NAME, r.pkg); + if (r.importance != DEFAULT_IMPORTANCE) { + out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance)); + } + if (r.priority != DEFAULT_PRIORITY) { + out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority)); + } + if (r.visibility != DEFAULT_VISIBILITY) { + out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility)); + } + out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge)); - if (!forBackup) { - out.attribute(null, ATT_UID, Integer.toString(r.uid)); - } + if (!forBackup) { + out.attribute(null, ATT_UID, Integer.toString(r.uid)); + } - for (NotificationChannelGroup group : r.groups.values()) { - group.writeXml(out); - } + for (NotificationChannelGroup group : r.groups.values()) { + group.writeXml(out); + } - for (NotificationChannel channel : r.channels.values()) { - if (!forBackup || (forBackup && !channel.isDeleted())) { - channel.writeXml(out); + for (NotificationChannel channel : r.channels.values()) { + if (!forBackup || (forBackup && !channel.isDeleted())) { + channel.writeXml(out); + } } - } - out.endTag(null, TAG_PACKAGE); + out.endTag(null, TAG_PACKAGE); + } } } out.endTag(null, TAG_RANKING); @@ -814,7 +821,9 @@ public class RankingHelper implements RankingConfig { pw.println("per-package config:"); } pw.println("Records:"); - dumpRecords(pw, prefix, filter, mRecords); + synchronized (mRecords) { + dumpRecords(pw, prefix, filter, mRecords); + } pw.println("Restored without uid:"); dumpRecords(pw, prefix, filter, mRestoredWithoutUids); } @@ -870,36 +879,38 @@ public class RankingHelper implements RankingConfig { } catch (JSONException e) { // pass } - final int N = mRecords.size(); - for (int i = 0; i < N; i++) { - final Record r = mRecords.valueAt(i); - if (filter == null || filter.matches(r.pkg)) { - JSONObject record = new JSONObject(); - try { - record.put("userId", UserHandle.getUserId(r.uid)); - record.put("packageName", r.pkg); - if (r.importance != DEFAULT_IMPORTANCE) { - record.put("importance", Ranking.importanceToString(r.importance)); - } - if (r.priority != DEFAULT_PRIORITY) { - record.put("priority", Notification.priorityToString(r.priority)); - } - if (r.visibility != DEFAULT_VISIBILITY) { - record.put("visibility", Notification.visibilityToString(r.visibility)); - } - if (r.showBadge != DEFAULT_SHOW_BADGE) { - record.put("showBadge", Boolean.valueOf(r.showBadge)); - } - for (NotificationChannel channel : r.channels.values()) { - record.put("channel", channel.toJson()); - } - for (NotificationChannelGroup group : r.groups.values()) { - record.put("group", group.toJson()); + synchronized (mRecords) { + final int N = mRecords.size(); + for (int i = 0; i < N; i++) { + final Record r = mRecords.valueAt(i); + if (filter == null || filter.matches(r.pkg)) { + JSONObject record = new JSONObject(); + try { + record.put("userId", UserHandle.getUserId(r.uid)); + record.put("packageName", r.pkg); + if (r.importance != DEFAULT_IMPORTANCE) { + record.put("importance", Ranking.importanceToString(r.importance)); + } + if (r.priority != DEFAULT_PRIORITY) { + record.put("priority", Notification.priorityToString(r.priority)); + } + if (r.visibility != DEFAULT_VISIBILITY) { + record.put("visibility", Notification.visibilityToString(r.visibility)); + } + if (r.showBadge != DEFAULT_SHOW_BADGE) { + record.put("showBadge", Boolean.valueOf(r.showBadge)); + } + for (NotificationChannel channel : r.channels.values()) { + record.put("channel", channel.toJson()); + } + for (NotificationChannelGroup group : r.groups.values()) { + record.put("group", group.toJson()); + } + } catch (JSONException e) { + // pass } - } catch (JSONException e) { - // pass + records.put(record); } - records.put(record); } } try { @@ -940,15 +951,18 @@ public class RankingHelper implements RankingConfig { } public Map<Integer, String> getPackageBans() { - final int N = mRecords.size(); - ArrayMap<Integer, String> packageBans = new ArrayMap<>(N); - for (int i = 0; i < N; i++) { - final Record r = mRecords.valueAt(i); - if (r.importance == NotificationManager.IMPORTANCE_NONE) { - packageBans.put(r.uid, r.pkg); + synchronized (mRecords) { + final int N = mRecords.size(); + ArrayMap<Integer, String> packageBans = new ArrayMap<>(N); + for (int i = 0; i < N; i++) { + final Record r = mRecords.valueAt(i); + if (r.importance == NotificationManager.IMPORTANCE_NONE) { + packageBans.put(r.uid, r.pkg); + } } + + return packageBans; } - return packageBans; } /** @@ -981,15 +995,17 @@ public class RankingHelper implements RankingConfig { private Map<String, Integer> getPackageChannels() { ArrayMap<String, Integer> packageChannels = new ArrayMap<>(); - for (int i = 0; i < mRecords.size(); i++) { - final Record r = mRecords.valueAt(i); - int channelCount = 0; - for (int j = 0; j < r.channels.size();j++) { - if (!r.channels.valueAt(j).isDeleted()) { - channelCount++; + synchronized (mRecords) { + for (int i = 0; i < mRecords.size(); i++) { + final Record r = mRecords.valueAt(i); + int channelCount = 0; + for (int j = 0; j < r.channels.size(); j++) { + if (!r.channels.valueAt(j).isDeleted()) { + channelCount++; + } } + packageChannels.put(r.pkg, channelCount); } - packageChannels.put(r.pkg, channelCount); } return packageChannels; } @@ -1006,7 +1022,9 @@ public class RankingHelper implements RankingConfig { for (int i = 0; i < size; i++) { final String pkg = pkgList[i]; final int uid = uidList[i]; - mRecords.remove(recordKey(pkg, uid)); + synchronized (mRecords) { + mRecords.remove(recordKey(pkg, uid)); + } mRestoredWithoutUids.remove(pkg); updated = true; } @@ -1018,7 +1036,9 @@ public class RankingHelper implements RankingConfig { try { r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId); mRestoredWithoutUids.remove(pkg); - mRecords.put(recordKey(r.pkg, r.uid), r); + synchronized (mRecords) { + mRecords.put(recordKey(r.pkg, r.uid), r); + } updated = true; } catch (NameNotFoundException e) { // noop diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java index d0dfc6cc4fe8..122a954b4d30 100644 --- a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java +++ b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java @@ -17,12 +17,15 @@ package com.android.server.print; +import static com.android.internal.util.CollectionUtils.size; import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkState; import android.Manifest; import android.annotation.CheckResult; import android.annotation.Nullable; +import android.app.PendingIntent; import android.companion.AssociationRequest; import android.companion.CompanionDeviceManager; import android.companion.ICompanionDeviceDiscoveryService; @@ -46,13 +49,18 @@ import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.provider.Settings; +import android.provider.SettingsStringUtil.ComponentNameSet; +import android.text.BidiFormatter; import android.util.AtomicFile; import android.util.ExceptionUtils; +import android.util.Log; import android.util.Slog; import android.util.Xml; import com.android.internal.app.IAppOpsService; import com.android.internal.content.PackageMonitor; +import com.android.internal.notification.NotificationAccessConfirmationActivityContract; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.server.FgThread; @@ -79,6 +87,7 @@ import java.util.function.Function; //TODO schedule stopScan on activity destroy(except if configuration change) //TODO on associate called again after configuration change -> replace old callback with new //TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example) +//TODO check user-feature present in manifest on API calls /** @hide */ public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient { @@ -140,10 +149,10 @@ public class CompanionDeviceManagerService extends SystemService implements Bind @Override public void binderDied() { - Handler.getMain().post(this::handleBinderDied); + Handler.getMain().post(this::cleanup); } - private void handleBinderDied() { + private void cleanup() { mServiceConnection = unbind(mServiceConnection); mFindDeviceCallback = unlinkToDeath(mFindDeviceCallback, this, 0); } @@ -207,7 +216,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } } - @Override public List<String> getAssociations(String callingPackage, int userId) throws RemoteException { @@ -217,12 +225,13 @@ public class CompanionDeviceManagerService extends SystemService implements Bind a -> a.deviceAddress); } + //TODO also revoke notification access @Override public void disassociate(String deviceMacAddress, String callingPackage) throws RemoteException { checkNotNull(deviceMacAddress); checkCallerIsSystemOr(callingPackage); - updateAssociations(associations -> ArrayUtils.remove(associations, + updateAssociations(associations -> CollectionUtils.remove(associations, new Association(getCallingUserId(), deviceMacAddress, callingPackage))); } @@ -237,11 +246,49 @@ public class CompanionDeviceManagerService extends SystemService implements Bind checkArgument(getCallingUserId() == userId, "Must be called by either same user or system"); - mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg); } + + @Override + public PendingIntent requestNotificationAccess(ComponentName component) + throws RemoteException { + String callingPackage = component.getPackageName(); + checkCanCallNotificationApi(callingPackage); + int userId = getCallingUserId(); + String packageTitle = BidiFormatter.getInstance().unicodeWrap( + getPackageInfo(callingPackage, userId) + .applicationInfo + .loadSafeLabel(getContext().getPackageManager()) + .toString()); + long identity = Binder.clearCallingIdentity(); + try { + return PendingIntent.getActivity(getContext(), + 0 /* request code */, + NotificationAccessConfirmationActivityContract.launcherIntent( + userId, component, packageTitle), + PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_CANCEL_CURRENT); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public boolean hasNotificationAccess(ComponentName component) throws RemoteException { + checkCanCallNotificationApi(component.getPackageName()); + String setting = Settings.Secure.getString(getContext().getContentResolver(), + Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); + return new ComponentNameSet(setting).contains(component); + } + + private void checkCanCallNotificationApi(String callingPackage) throws RemoteException { + checkCallerIsSystemOr(callingPackage); + checkState(!ArrayUtils.isEmpty(readAllAssociations(getCallingUserId(), callingPackage)), + "App must have an association before calling this API"); + } } + private int getCallingUserId() { return UserHandle.getUserId(Binder.getCallingUid()); } @@ -263,7 +310,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind mFindDeviceCallback.asBinder().linkToDeath( CompanionDeviceManagerService.this, 0); } catch (RemoteException e) { - handleBinderDied(); + cleanup(); return; } try { @@ -291,10 +338,26 @@ public class CompanionDeviceManagerService extends SystemService implements Bind return new ICompanionDeviceDiscoveryServiceCallback.Stub() { @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (Throwable e) { + Slog.e(LOG_TAG, "Error during IPC", e); + throw ExceptionUtils.propagate(e, RemoteException.class); + } + } + + @Override public void onDeviceSelected(String packageName, int userId, String deviceAddress) { - //TODO unbind updateSpecialAccessPermissionForAssociatedPackage(packageName, userId); recordAssociation(packageName, deviceAddress); + cleanup(); + } + + @Override + public void onDeviceSelectionCancel() { + cleanup(); } }; } @@ -345,22 +408,29 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } private void recordAssociation(String priviledgedPackage, String deviceAddress) { - updateAssociations((associations) -> ArrayUtils.add(associations, - new Association(getCallingUserId(), deviceAddress, priviledgedPackage))); + if (DEBUG) { + Log.i(LOG_TAG, "recordAssociation(priviledgedPackage = " + priviledgedPackage + + ", deviceAddress = " + deviceAddress + ")"); + } + int userId = getCallingUserId(); + updateAssociations(associations -> CollectionUtils.add(associations, + new Association(userId, deviceAddress, priviledgedPackage))); } - private void updateAssociations(Function<ArrayList<Association>, List<Association>> update) { + private void updateAssociations(Function<List<Association>, List<Association>> update) { updateAssociations(update, getCallingUserId()); } - private void updateAssociations(Function<ArrayList<Association>, List<Association>> update, + private void updateAssociations(Function<List<Association>, List<Association>> update, int userId) { final AtomicFile file = getStorageFileForUser(userId); synchronized (file) { - final ArrayList<Association> old = readAllAssociations(userId); - final List<Association> associations = update.apply(old); - if (Objects.equals(old, associations)) return; + List<Association> associations = readAllAssociations(userId); + final List<Association> old = CollectionUtils.copyOf(associations); + associations = update.apply(associations); + if (size(old) == size(associations)) return; + List<Association> finalAssociations = associations; file.write((out) -> { XmlSerializer xml = Xml.newSerializer(); try { @@ -369,8 +439,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind xml.startDocument(null, true); xml.startTag(null, XML_TAG_ASSOCIATIONS); - for (int i = 0; i < CollectionUtils.size(associations); i++) { - Association association = associations.get(i); + for (int i = 0; i < size(finalAssociations); i++) { + Association association = finalAssociations.get(i); xml.startTag(null, XML_TAG_ASSOCIATION) .attribute(null, XML_ATTR_PACKAGE, association.companionAppPackage) .attribute(null, XML_ATTR_DEVICE, association.deviceAddress) @@ -386,15 +456,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind }); } - - - //TODO Show dialog before recording notification access -// final SettingStringHelper setting = -// new SettingStringHelper( -// getContext().getContentResolver(), -// Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, -// getUserId()); -// setting.write(ColonDelimitedSet.OfStrings.add(setting.read(), priviledgedPackage)); } private AtomicFile getStorageFileForUser(int uid) { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c562cb95ee31..7c7a3f83a826 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -42,6 +42,7 @@ import android.net.INetworkStatsService; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.MatchAllNetworkSpecifier; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; @@ -51,7 +52,9 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; import android.net.RouteInfo; +import android.net.StringNetworkSpecifier; import android.net.metrics.IpConnectivityLog; import android.net.util.MultinetworkPolicyTracker; import android.os.ConditionVariable; @@ -64,12 +67,15 @@ import android.os.Message; import android.os.MessageQueue; import android.os.Messenger; import android.os.MessageQueue.IdleHandler; +import android.os.Parcel; +import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; import android.provider.Settings; import android.test.AndroidTestCase; import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.SmallTest; +import android.text.TextUtils; import android.util.Log; import android.util.LogPrinter; @@ -319,6 +325,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); } + public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) { + mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + public void connectWithoutInternet() { mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); mNetworkAgent.sendNetworkInfo(mNetworkInfo); @@ -1819,34 +1830,130 @@ public class ConnectivityServiceTest extends AndroidTestCase { captivePortalCallback.assertNoCallback(); } + private NetworkRequest.Builder newWifiRequestBuilder() { + return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI); + } + @SmallTest - public void testInvalidNetworkSpecifier() { - boolean execptionCalled = true; + public void testNetworkSpecifier() { + NetworkRequest rEmpty1 = newWifiRequestBuilder().build(); + NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build(); + NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build(); + NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier( + (NetworkSpecifier) null).build(); + NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier("foo").build(); + NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier( + new StringNetworkSpecifier("bar")).build(); + + TestNetworkCallback cEmpty1 = new TestNetworkCallback(); + TestNetworkCallback cEmpty2 = new TestNetworkCallback(); + TestNetworkCallback cEmpty3 = new TestNetworkCallback(); + TestNetworkCallback cEmpty4 = new TestNetworkCallback(); + TestNetworkCallback cFoo = new TestNetworkCallback(); + TestNetworkCallback cBar = new TestNetworkCallback(); + TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] { + cEmpty1, cEmpty2, cEmpty3 }; + + mCm.registerNetworkCallback(rEmpty1, cEmpty1); + mCm.registerNetworkCallback(rEmpty2, cEmpty2); + mCm.registerNetworkCallback(rEmpty3, cEmpty3); + mCm.registerNetworkCallback(rEmpty4, cEmpty4); + mCm.registerNetworkCallback(rFoo, cFoo); + mCm.registerNetworkCallback(rBar, cBar); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + cEmpty1.expectAvailableCallbacks(mWiFiNetworkAgent); + cEmpty2.expectAvailableCallbacks(mWiFiNetworkAgent); + cEmpty3.expectAvailableCallbacks(mWiFiNetworkAgent); + cEmpty4.expectAvailableCallbacks(mWiFiNetworkAgent); + assertNoCallbacks(cFoo, cBar); + + mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo")); + cFoo.expectAvailableCallbacks(mWiFiNetworkAgent); + for (TestNetworkCallback c: emptyCallbacks) { + c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + } + cFoo.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + cFoo.assertNoCallback(); + + mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar")); + cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + cBar.expectAvailableCallbacks(mWiFiNetworkAgent); + for (TestNetworkCallback c: emptyCallbacks) { + c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + } + cBar.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + cBar.assertNoCallback(); + + mWiFiNetworkAgent.setNetworkSpecifier(null); + cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + for (TestNetworkCallback c: emptyCallbacks) { + c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + } + + assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar); + } + @SmallTest + public void testInvalidNetworkSpecifier() { try { NetworkRequest.Builder builder = new NetworkRequest.Builder(); - builder.setNetworkSpecifier(MATCH_ALL_REQUESTS_NETWORK_SPECIFIER); - execptionCalled = false; - } catch (IllegalArgumentException e) { - // do nothing - should get here + builder.setNetworkSpecifier(new MatchAllNetworkSpecifier()); + fail("NetworkRequest builder with MatchAllNetworkSpecifier"); + } catch (IllegalArgumentException expected) { + // expected } - assertTrue("NetworkRequest builder with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER", - execptionCalled); - try { NetworkCapabilities networkCapabilities = new NetworkCapabilities(); networkCapabilities.addTransportType(TRANSPORT_WIFI) - .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER); + .setNetworkSpecifier(new MatchAllNetworkSpecifier()); mService.requestNetwork(networkCapabilities, null, 0, null, ConnectivityManager.TYPE_WIFI); - execptionCalled = false; - } catch (IllegalArgumentException e) { - // do nothing - should get here + fail("ConnectivityService requestNetwork with MatchAllNetworkSpecifier"); + } catch (IllegalArgumentException expected) { + // expected + } + + class NonParcelableSpecifier extends NetworkSpecifier { + public boolean satisfiedBy(NetworkSpecifier other) { return false; } + }; + class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable { + @Override public int describeContents() { return 0; } + @Override public void writeToParcel(Parcel p, int flags) {} + } + NetworkRequest.Builder builder; + + builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET); + try { + builder.setNetworkSpecifier(new NonParcelableSpecifier()); + Parcel parcelW = Parcel.obtain(); + builder.build().writeToParcel(parcelW, 0); + fail("Parceling a non-parcelable specifier did not throw an exception"); + } catch (Exception e) { + // expected } - assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER", - execptionCalled); + builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET); + builder.setNetworkSpecifier(new ParcelableSpecifier()); + NetworkRequest nr = builder.build(); + assertNotNull(nr); + + try { + Parcel parcelW = Parcel.obtain(); + nr.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR); + fail("Unparceling a non-framework NetworkSpecifier did not throw an exception"); + } catch (Exception e) { + // expected + } } @SmallTest |