diff options
577 files changed, 9892 insertions, 6321 deletions
diff --git a/api/current.txt b/api/current.txt index 4149d03ffeac..b51ea542fa10 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(); @@ -3847,7 +3848,7 @@ package android.app { method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException; method public java.util.List<android.app.ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException; - method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; + method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException; method public deprecated boolean isInLockTaskMode(); method public boolean isLowRamDevice(); @@ -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 @@ -5602,7 +5604,6 @@ package android.app { method public boolean removeAutomaticZenRule(java.lang.String); method public final void setInterruptionFilter(int); method public void setNotificationPolicy(android.app.NotificationManager.Policy); - method public deprecated android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification); method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule); field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED"; field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED"; @@ -6090,6 +6091,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 +6124,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 +6140,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 +6149,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 +6174,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 { @@ -6604,7 +6624,7 @@ package android.app.assist { public static class AssistStructure.ViewNode { method public float getAlpha(); - method public java.lang.String[] getAutoFillHints(); + method public java.lang.String[] getAutofillHints(); method public android.view.autofill.AutofillId getAutofillId(); method public java.lang.String[] getAutofillOptions(); method public int getAutofillType(); @@ -6868,6 +6888,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.app.Service); + 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); @@ -6965,12 +6993,12 @@ package android.app.usage { } public class StorageStatsManager { - method public long getFreeBytes(java.lang.String); - method public long getTotalBytes(java.lang.String); - method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int); - method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle); + method public long getFreeBytes(java.util.UUID) throws java.io.IOException; + method public long getTotalBytes(java.util.UUID) throws java.io.IOException; + method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForPackage(java.util.UUID, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public android.app.usage.StorageStats queryStatsForUid(java.util.UUID, int) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; } public final class UsageEvents implements android.os.Parcelable { @@ -8068,7 +8096,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 { @@ -8243,7 +8276,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); } @@ -8251,6 +8285,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"; } @@ -9323,7 +9359,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"; @@ -10181,12 +10216,12 @@ package android.content.pm { field public java.lang.String[] splitNames; field public java.lang.String[] splitPublicSourceDirs; field public java.lang.String[] splitSourceDirs; + field public java.util.UUID storageUuid; field public int targetSdkVersion; field public java.lang.String taskAffinity; field public int theme; field public int uiOptions; field public int uid; - field public java.lang.String volumeUuid; } public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator { @@ -10305,7 +10340,7 @@ package android.content.pm { public class LauncherApps { method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); - method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle); + method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent); method public java.util.List<android.os.UserHandle> getProfiles(); method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int); @@ -12533,6 +12568,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; @@ -21869,7 +21905,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(); @@ -21967,6 +22003,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); } @@ -22422,7 +22471,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(); @@ -22457,6 +22506,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); @@ -22682,69 +22737,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,8 +22774,8 @@ package android.media { method public android.media.MediaPlayer.DrmInfo getDrmInfo(); method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException; method public int getDuration(); - method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; - method public android.media.MediaMetricsSet getMetrics(); + method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; + method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); @@ -22796,7 +22788,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -22823,7 +22815,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); - method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); + method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -22864,6 +22856,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2 + field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 field public static final int SEEK_CLOSEST = 3; // 0x3 field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 field public static final int SEEK_NEXT_SYNC = 1; // 0x1 @@ -22873,11 +22869,25 @@ package android.media { } public static final class MediaPlayer.DrmInfo { - method public java.lang.String[] getMimes(); method public java.util.Map<java.util.UUID, byte[]> getPssh(); method public java.util.UUID[] getSupportedSchemes(); } + 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); } @@ -22890,7 +22900,7 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract interface MediaPlayer.OnDrmConfigListener { + public static abstract interface MediaPlayer.OnDrmConfigHelper { method public abstract void onDrmConfig(android.media.MediaPlayer); } @@ -22899,7 +22909,7 @@ package android.media { } public static abstract interface MediaPlayer.OnDrmPreparedListener { - method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean); + method public abstract void onDrmPrepared(android.media.MediaPlayer, int); } public static abstract interface MediaPlayer.OnErrorListener { @@ -22930,8 +22940,12 @@ package android.media { method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int); } - public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException { - ctor public MediaPlayer.ProvisioningErrorException(java.lang.String); + public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String); + } + + public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String); } public static class MediaPlayer.TrackInfo implements android.os.Parcelable { @@ -22952,7 +22966,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; @@ -22971,11 +22985,12 @@ package android.media { method public void setMaxDuration(int) throws java.lang.IllegalArgumentException; method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException; method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalStateException; - method public void setNextOutputFile(java.lang.String) throws java.io.IOException, java.lang.IllegalStateException; + method public void setNextOutputFile(java.io.File) throws java.io.IOException, java.lang.IllegalStateException; method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener); method public void setOnInfoListener(android.media.MediaRecorder.OnInfoListener); method public void setOrientationHint(int); method public void setOutputFile(java.io.FileDescriptor) throws java.lang.IllegalStateException; + method public void setOutputFile(java.io.File); method public void setOutputFile(java.lang.String) throws java.lang.IllegalStateException; method public void setOutputFormat(int) throws java.lang.IllegalStateException; method public void setPreviewDisplay(android.view.Surface); @@ -23020,6 +23035,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); } @@ -23983,7 +24017,6 @@ package android.media.browse { method public android.content.ComponentName getServiceComponent(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isConnected(); - method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback); method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback); method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback); method public void unsubscribe(java.lang.String); @@ -24019,12 +24052,6 @@ package android.media.browse { field public static final int FLAG_PLAYABLE = 2; // 0x2 } - public static abstract class MediaBrowser.SearchCallback { - ctor public MediaBrowser.SearchCallback(); - method public void onError(java.lang.String, android.os.Bundle); - method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>); - } - public static abstract class MediaBrowser.SubscriptionCallback { ctor public MediaBrowser.SubscriptionCallback(); method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>); @@ -24233,8 +24260,6 @@ package android.media.session { public final class MediaController { ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token); - method public void addQueueItem(android.media.MediaDescription); - method public void addQueueItem(android.media.MediaDescription, int); method public void adjustVolume(int, int); method public boolean dispatchMediaButtonEvent(android.view.KeyEvent); method public android.os.Bundle getExtras(); @@ -24246,15 +24271,11 @@ package android.media.session { method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue(); method public java.lang.CharSequence getQueueTitle(); method public int getRatingType(); - method public int getRepeatMode(); method public android.app.PendingIntent getSessionActivity(); method public android.media.session.MediaSession.Token getSessionToken(); method public android.media.session.MediaController.TransportControls getTransportControls(); - method public boolean isShuffleModeEnabled(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); - method public void removeQueueItem(android.media.MediaDescription); - method public void removeQueueItemAt(int); method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void setVolumeTo(int, int); method public void unregisterCallback(android.media.session.MediaController.Callback); @@ -24268,10 +24289,8 @@ package android.media.session { method public void onPlaybackStateChanged(android.media.session.PlaybackState); method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>); method public void onQueueTitleChanged(java.lang.CharSequence); - method public void onRepeatModeChanged(int); method public void onSessionDestroyed(); method public void onSessionEvent(java.lang.String, android.os.Bundle); - method public void onShuffleModeChanged(boolean); } public static final class MediaController.PlaybackInfo { @@ -24300,8 +24319,6 @@ package android.media.session { method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle); method public void sendCustomAction(java.lang.String, android.os.Bundle); method public void setRating(android.media.Rating); - method public void setRepeatMode(int); - method public void setShuffleModeEnabled(boolean); method public void skipToNext(); method public void skipToPrevious(); method public void skipToQueueItem(long); @@ -24328,18 +24345,13 @@ package android.media.session { method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>); method public void setQueueTitle(java.lang.CharSequence); method public void setRatingType(int); - method public void setRepeatMode(int); method public void setSessionActivity(android.app.PendingIntent); - method public void setShuffleModeEnabled(boolean); field public static final deprecated int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 - field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4 field public static final deprecated int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } public static abstract class MediaSession.Callback { ctor public MediaSession.Callback(); - method public void onAddQueueItem(android.media.MediaDescription); - method public void onAddQueueItem(android.media.MediaDescription, int); method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void onCustomAction(java.lang.String, android.os.Bundle); method public void onFastForward(); @@ -24353,13 +24365,9 @@ package android.media.session { method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle); method public void onPrepareFromSearch(java.lang.String, android.os.Bundle); method public void onPrepareFromUri(android.net.Uri, android.os.Bundle); - method public void onRemoveQueueItem(android.media.MediaDescription); - method public void onRemoveQueueItemAt(int); method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); - method public void onSetRepeatMode(int); - method public void onSetShuffleModeEnabled(boolean); method public void onSkipToNext(); method public void onSkipToPrevious(); method public void onSkipToQueueItem(long); @@ -24420,17 +24428,12 @@ package android.media.session { field public static final long ACTION_REWIND = 8L; // 0x8L field public static final long ACTION_SEEK_TO = 256L; // 0x100L field public static final long ACTION_SET_RATING = 128L; // 0x80L - field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L - field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L field public static final long ACTION_STOP = 1L; // 0x1L field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR; field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL - field public static final int REPEAT_MODE_ALL = 2; // 0x2 - field public static final int REPEAT_MODE_NONE = 0; // 0x0 - field public static final int REPEAT_MODE_ONE = 1; // 0x1 field public static final int STATE_BUFFERING = 6; // 0x6 field public static final int STATE_CONNECTING = 8; // 0x8 field public static final int STATE_ERROR = 7; // 0x7 @@ -25779,6 +25782,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 { @@ -26751,8 +26758,8 @@ package android.net.wifi.aware { } public class DiscoverySession { - method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); - method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); method public void destroy(); method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]); } @@ -26838,8 +26845,8 @@ package android.net.wifi.aware { } public class WifiAwareSession { - method public java.lang.String createNetworkSpecifierOpen(int, byte[]); - method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String); method public void destroy(); method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); @@ -30770,6 +30777,7 @@ package android.os { method public android.util.SizeF getSizeF(java.lang.String); method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String); method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String); + method public java.util.UUID getUuid(java.lang.String); method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); method public void putBinder(java.lang.String, android.os.IBinder); @@ -30794,6 +30802,7 @@ package android.os { method public void putSizeF(java.lang.String, android.util.SizeF); method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>); method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>); + method public void putUuid(java.lang.String, java.util.UUID); method public void readFromParcel(android.os.Parcel); method public void setClassLoader(java.lang.ClassLoader); method public void writeToParcel(android.os.Parcel, int); @@ -31323,6 +31332,7 @@ package android.os { method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>); + method public final java.util.UUID readUuid(); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -31368,6 +31378,7 @@ package android.os { method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int); method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); method public final <T extends android.os.Parcelable> void writeTypedObject(T, int); + method public final void writeUuid(java.util.UUID); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -31998,15 +32009,16 @@ package android.os.storage { } public class StorageManager { - method public void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException; method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException; - method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException; - method public long getCacheQuotaBytes(java.io.File); - method public long getCacheSizeBytes(java.io.File); + method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException; + method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException; + method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException; method public java.lang.String getMountedObbPath(java.lang.String); method public android.os.storage.StorageVolume getPrimaryStorageVolume(); method public android.os.storage.StorageVolume getStorageVolume(java.io.File); method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes(); + method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException; method public boolean isEncrypted(java.io.File); @@ -32018,7 +32030,10 @@ package android.os.storage { method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException; method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener); field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; + field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID"; field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final java.util.UUID UUID_DEFAULT; } public final class StorageVolume implements android.os.Parcelable { @@ -35455,6 +35470,16 @@ package android.provider { field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id"; } + public static final class Telephony.ServiceStateTable { + method public static android.net.Uri getUriForSubId(int); + method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String); + field public static final java.lang.String AUTHORITY = "service-state"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + field public static final java.lang.String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + field public static final java.lang.String VOICE_REG_STATE = "voice_reg_state"; + } + public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns { method public static java.lang.String getDefaultSmsPackage(android.content.Context); field public static final android.net.Uri CONTENT_URI; @@ -37032,8 +37057,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"; } @@ -37058,6 +37085,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); @@ -37069,7 +37115,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); } @@ -37096,6 +37143,15 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); + method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); + } + + public final class SaveRequest implements android.os.Parcelable { + 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; } } @@ -37279,7 +37335,6 @@ package android.service.media { method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle); method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>); - method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; } @@ -37359,16 +37414,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String); - method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); + method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -37381,7 +37436,7 @@ package android.service.notification { method public final void requestUnbind(); method public final void setNotificationsShown(java.lang.String[]); method public final void snoozeNotification(java.lang.String, long); - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 @@ -37731,10 +37786,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(); @@ -39409,6 +39466,8 @@ package android.telecom { field public static final java.lang.String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT"; field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED"; field public static final deprecated java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL"; + field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED"; + field public static final java.lang.String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED"; field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS"; field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS"; field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION"; @@ -40853,7 +40912,6 @@ package android.test.mock { method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException; method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException; method public android.content.ComponentName startService(android.content.Intent); - method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification); method public boolean stopService(android.content.Intent); method public void unbindService(android.content.ServiceConnection); method public void unregisterReceiver(android.content.BroadcastReceiver); @@ -45365,7 +45423,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(); @@ -45454,7 +45511,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(); @@ -45687,7 +45743,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); @@ -45843,9 +45898,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 @@ -46413,7 +46465,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); @@ -47800,7 +47851,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 { @@ -49674,6 +49725,7 @@ package android.widget { method public java.lang.String getFormat(); method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener(); method public boolean isCountDown(); + method public boolean isTheFinalCountDown(); method public void setBase(long); method public void setCountDown(boolean); method public void setFormat(java.lang.String); @@ -55343,6 +55395,7 @@ package java.lang.invoke { method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>); method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...); method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType); + method public static java.lang.invoke.MethodHandle explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType); method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...); method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle); method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle); diff --git a/api/removed.txt b/api/removed.txt index 82705fd981f9..0f5b81abad4c 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -5,10 +5,6 @@ package android.app { method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent); } - public static class Notification.Builder { - method public deprecated android.app.Notification.Builder chooseBadgeIcon(int); - } - public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable { method public deprecated void showAsNotification(android.content.Context); } @@ -26,6 +22,20 @@ package android.app.admin { } +package android.app.usage { + + public class StorageStatsManager { + method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException; + method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException; + method public deprecated boolean isQuotaSupported(java.lang.String); + method public deprecated android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public deprecated android.app.usage.StorageStats queryStatsForUid(java.lang.String, int) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + } + +} + package android.content { public abstract class Context { @@ -41,6 +51,10 @@ package android.content { package android.content.pm { + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { + field public deprecated java.lang.String volumeUuid; + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { field public deprecated boolean encryptionAware; } @@ -184,10 +198,14 @@ package android.os { package android.os.storage { public class StorageManager { - method public deprecated long getCacheQuotaBytes(); - method public deprecated long getCacheSizeBytes(); - method public deprecated long getExternalCacheQuotaBytes(); - method public deprecated long getExternalCacheSizeBytes(); + method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheSizeBytes() throws java.io.IOException; + method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException; method public android.os.storage.StorageVolume getPrimaryVolume(); method public android.os.storage.StorageVolume[] getVolumeList(); method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException; diff --git a/api/system-current.txt b/api/system-current.txt index 4fa96aef9eec..dc4c21fd2f30 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 @@ -1197,6 +1197,8 @@ package android { field public static final int requiredFeature = 16844119; // 0x1010557 field public static final int requiredForAllUsers = 16843728; // 0x10103d0 field public static final int requiredNotFeature = 16844120; // 0x1010558 + field public static final int requiredSystemPropertyName = 16844136; // 0x1010568 + field public static final int requiredSystemPropertyValue = 16844137; // 0x1010569 field public static final int requiresFadingEdge = 16843685; // 0x10103a5 field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364 field public static final int resizeClip = 16843983; // 0x10104cf @@ -3743,6 +3745,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(); @@ -3986,7 +3989,7 @@ package android.app { method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException; method public java.util.List<android.app.ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException; - method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; + method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException; method public int getUidImportance(int); method public deprecated boolean isInLockTaskMode(); @@ -4087,7 +4090,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 @@ -5802,7 +5806,6 @@ package android.app { method public boolean removeAutomaticZenRule(java.lang.String); method public final void setInterruptionFilter(int); method public void setNotificationPolicy(android.app.NotificationManager.Policy); - method public deprecated android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification); method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule); field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED"; field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED"; @@ -6294,6 +6297,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 +6330,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 +6348,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 +6357,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 +6385,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 { @@ -6847,7 +6869,7 @@ package android.app.assist { public static class AssistStructure.ViewNode { method public float getAlpha(); - method public java.lang.String[] getAutoFillHints(); + method public java.lang.String[] getAutofillHints(); method public android.view.autofill.AutofillId getAutofillId(); method public java.lang.String[] getAutofillOptions(); method public int getAutofillType(); @@ -7302,6 +7324,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.app.Service); + 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); @@ -7428,12 +7458,12 @@ package android.app.usage { } public class StorageStatsManager { - method public long getFreeBytes(java.lang.String); - method public long getTotalBytes(java.lang.String); - method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int); - method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle); + method public long getFreeBytes(java.util.UUID) throws java.io.IOException; + method public long getTotalBytes(java.util.UUID) throws java.io.IOException; + method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForPackage(java.util.UUID, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public android.app.usage.StorageStats queryStatsForUid(java.util.UUID, int) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; } public final class UsageEvents implements android.os.Parcelable { @@ -8540,10 +8570,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 { @@ -8737,7 +8772,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); } @@ -8745,6 +8781,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"; } @@ -10753,12 +10791,12 @@ package android.content.pm { field public java.lang.String[] splitNames; field public java.lang.String[] splitPublicSourceDirs; field public java.lang.String[] splitSourceDirs; + field public java.util.UUID storageUuid; field public int targetSdkVersion; field public java.lang.String taskAffinity; field public int theme; field public int uiOptions; field public int uid; - field public java.lang.String volumeUuid; } public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator { @@ -10967,7 +11005,7 @@ package android.content.pm { public class LauncherApps { method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); - method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle); + method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent); method public java.util.List<android.os.UserHandle> getProfiles(); method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int); @@ -11237,6 +11275,7 @@ package android.content.pm { method public abstract byte[] getInstantAppCookie(); method public abstract int getInstantAppCookieMaxSize(); method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String); + method public abstract android.content.ComponentName getInstantAppInstallerComponent(); method public abstract android.content.ComponentName getInstantAppResolverSettingsComponent(); method public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps(); method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -13303,6 +13342,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; @@ -23701,7 +23741,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(); @@ -23799,6 +23839,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); } @@ -24254,7 +24307,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(); @@ -24289,6 +24342,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); @@ -24514,69 +24573,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,8 +24610,8 @@ package android.media { method public android.media.MediaPlayer.DrmInfo getDrmInfo(); method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException; method public int getDuration(); - method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; - method public android.media.MediaMetricsSet getMetrics(); + method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; + method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); @@ -24628,7 +24624,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -24655,7 +24651,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); - method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); + method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -24696,6 +24692,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2 + field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 field public static final int SEEK_CLOSEST = 3; // 0x3 field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 field public static final int SEEK_NEXT_SYNC = 1; // 0x1 @@ -24705,11 +24705,25 @@ package android.media { } public static final class MediaPlayer.DrmInfo { - method public java.lang.String[] getMimes(); method public java.util.Map<java.util.UUID, byte[]> getPssh(); method public java.util.UUID[] getSupportedSchemes(); } + 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); } @@ -24722,7 +24736,7 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract interface MediaPlayer.OnDrmConfigListener { + public static abstract interface MediaPlayer.OnDrmConfigHelper { method public abstract void onDrmConfig(android.media.MediaPlayer); } @@ -24731,7 +24745,7 @@ package android.media { } public static abstract interface MediaPlayer.OnDrmPreparedListener { - method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean); + method public abstract void onDrmPrepared(android.media.MediaPlayer, int); } public static abstract interface MediaPlayer.OnErrorListener { @@ -24762,8 +24776,12 @@ package android.media { method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int); } - public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException { - ctor public MediaPlayer.ProvisioningErrorException(java.lang.String); + public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String); + } + + public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String); } public static class MediaPlayer.TrackInfo implements android.os.Parcelable { @@ -24784,7 +24802,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; @@ -24803,11 +24821,12 @@ package android.media { method public void setMaxDuration(int) throws java.lang.IllegalArgumentException; method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException; method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalStateException; - method public void setNextOutputFile(java.lang.String) throws java.io.IOException, java.lang.IllegalStateException; + method public void setNextOutputFile(java.io.File) throws java.io.IOException, java.lang.IllegalStateException; method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener); method public void setOnInfoListener(android.media.MediaRecorder.OnInfoListener); method public void setOrientationHint(int); method public void setOutputFile(java.io.FileDescriptor) throws java.lang.IllegalStateException; + method public void setOutputFile(java.io.File); method public void setOutputFile(java.lang.String) throws java.lang.IllegalStateException; method public void setOutputFormat(int) throws java.lang.IllegalStateException; method public void setPreviewDisplay(android.view.Surface); @@ -24854,6 +24873,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); } @@ -25901,7 +25939,6 @@ package android.media.browse { method public android.content.ComponentName getServiceComponent(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isConnected(); - method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback); method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback); method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback); method public void unsubscribe(java.lang.String); @@ -25937,12 +25974,6 @@ package android.media.browse { field public static final int FLAG_PLAYABLE = 2; // 0x2 } - public static abstract class MediaBrowser.SearchCallback { - ctor public MediaBrowser.SearchCallback(); - method public void onError(java.lang.String, android.os.Bundle); - method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>); - } - public static abstract class MediaBrowser.SubscriptionCallback { ctor public MediaBrowser.SubscriptionCallback(); method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>); @@ -26151,8 +26182,6 @@ package android.media.session { public final class MediaController { ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token); - method public void addQueueItem(android.media.MediaDescription); - method public void addQueueItem(android.media.MediaDescription, int); method public void adjustVolume(int, int); method public boolean dispatchMediaButtonEvent(android.view.KeyEvent); method public android.os.Bundle getExtras(); @@ -26164,15 +26193,11 @@ package android.media.session { method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue(); method public java.lang.CharSequence getQueueTitle(); method public int getRatingType(); - method public int getRepeatMode(); method public android.app.PendingIntent getSessionActivity(); method public android.media.session.MediaSession.Token getSessionToken(); method public android.media.session.MediaController.TransportControls getTransportControls(); - method public boolean isShuffleModeEnabled(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); - method public void removeQueueItem(android.media.MediaDescription); - method public void removeQueueItemAt(int); method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void setVolumeTo(int, int); method public void unregisterCallback(android.media.session.MediaController.Callback); @@ -26186,10 +26211,8 @@ package android.media.session { method public void onPlaybackStateChanged(android.media.session.PlaybackState); method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>); method public void onQueueTitleChanged(java.lang.CharSequence); - method public void onRepeatModeChanged(int); method public void onSessionDestroyed(); method public void onSessionEvent(java.lang.String, android.os.Bundle); - method public void onShuffleModeChanged(boolean); } public static final class MediaController.PlaybackInfo { @@ -26218,8 +26241,6 @@ package android.media.session { method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle); method public void sendCustomAction(java.lang.String, android.os.Bundle); method public void setRating(android.media.Rating); - method public void setRepeatMode(int); - method public void setShuffleModeEnabled(boolean); method public void skipToNext(); method public void skipToPrevious(); method public void skipToQueueItem(long); @@ -26246,18 +26267,13 @@ package android.media.session { method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>); method public void setQueueTitle(java.lang.CharSequence); method public void setRatingType(int); - method public void setRepeatMode(int); method public void setSessionActivity(android.app.PendingIntent); - method public void setShuffleModeEnabled(boolean); field public static final deprecated int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 - field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4 field public static final deprecated int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } public static abstract class MediaSession.Callback { ctor public MediaSession.Callback(); - method public void onAddQueueItem(android.media.MediaDescription); - method public void onAddQueueItem(android.media.MediaDescription, int); method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void onCustomAction(java.lang.String, android.os.Bundle); method public void onFastForward(); @@ -26271,13 +26287,9 @@ package android.media.session { method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle); method public void onPrepareFromSearch(java.lang.String, android.os.Bundle); method public void onPrepareFromUri(android.net.Uri, android.os.Bundle); - method public void onRemoveQueueItem(android.media.MediaDescription); - method public void onRemoveQueueItemAt(int); method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); - method public void onSetRepeatMode(int); - method public void onSetShuffleModeEnabled(boolean); method public void onSkipToNext(); method public void onSkipToPrevious(); method public void onSkipToQueueItem(long); @@ -26348,17 +26360,12 @@ package android.media.session { field public static final long ACTION_REWIND = 8L; // 0x8L field public static final long ACTION_SEEK_TO = 256L; // 0x100L field public static final long ACTION_SET_RATING = 128L; // 0x80L - field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L - field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L field public static final long ACTION_STOP = 1L; // 0x1L field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR; field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL - field public static final int REPEAT_MODE_ALL = 2; // 0x2 - field public static final int REPEAT_MODE_NONE = 0; // 0x0 - field public static final int REPEAT_MODE_ONE = 1; // 0x1 field public static final int STATE_BUFFERING = 6; // 0x6 field public static final int STATE_CONNECTING = 8; // 0x8 field public static final int STATE_ERROR = 7; // 0x7 @@ -28001,6 +28008,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 { @@ -28019,6 +28027,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; } @@ -28141,10 +28152,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; @@ -28152,9 +28159,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(); @@ -29497,9 +29501,9 @@ package android.net.wifi.aware { } public class DiscoverySession { - method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); - method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); - method public java.lang.String createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]); method public void destroy(); method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]); } @@ -29585,9 +29589,9 @@ package android.net.wifi.aware { } public class WifiAwareSession { - method public java.lang.String createNetworkSpecifierOpen(int, byte[]); - method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); - method public java.lang.String createNetworkSpecifierPmk(int, byte[], byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, byte[], byte[]); method public void destroy(); method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); @@ -33532,6 +33536,7 @@ package android.os { method public android.util.SizeF getSizeF(java.lang.String); method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String); method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String); + method public java.util.UUID getUuid(java.lang.String); method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); method public void putBinder(java.lang.String, android.os.IBinder); @@ -33556,6 +33561,7 @@ package android.os { method public void putSizeF(java.lang.String, android.util.SizeF); method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>); method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>); + method public void putUuid(java.lang.String, java.util.UUID); method public void readFromParcel(android.os.Parcel); method public void setClassLoader(java.lang.ClassLoader); method public void writeToParcel(android.os.Parcel, int); @@ -34115,6 +34121,7 @@ package android.os { method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>); + method public final java.util.UUID readUuid(); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -34160,6 +34167,7 @@ package android.os { method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int); method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); method public final <T extends android.os.Parcelable> void writeTypedObject(T, int); + method public final void writeUuid(java.util.UUID); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -34895,15 +34903,16 @@ package android.os.storage { } public class StorageManager { - method public void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException; method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException; - method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException; - method public long getCacheQuotaBytes(java.io.File); - method public long getCacheSizeBytes(java.io.File); + method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException; + method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException; + method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException; method public java.lang.String getMountedObbPath(java.lang.String); method public android.os.storage.StorageVolume getPrimaryStorageVolume(); method public android.os.storage.StorageVolume getStorageVolume(java.io.File); method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes(); + method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException; method public boolean isEncrypted(java.io.File); @@ -34915,7 +34924,10 @@ package android.os.storage { method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException; method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener); field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; + field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID"; field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final java.util.UUID UUID_DEFAULT; } public final class StorageVolume implements android.os.Parcelable { @@ -38109,7 +38121,6 @@ package android.provider { field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; field public static final java.lang.String MODE_RINGER = "mode_ringer"; field public static final java.lang.String NETWORK_PREFERENCE = "network_preference"; - field public static final java.lang.String NETWORK_RECOMMENDATIONS_ENABLED = "network_recommendations_enabled"; field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth"; field public static final java.lang.String RADIO_CELL = "cell"; @@ -38559,6 +38570,16 @@ package android.provider { field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id"; } + public static final class Telephony.ServiceStateTable { + method public static android.net.Uri getUriForSubId(int); + method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String); + field public static final java.lang.String AUTHORITY = "service-state"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + field public static final java.lang.String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + field public static final java.lang.String VOICE_REG_STATE = "voice_reg_state"; + } + public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns { method public static java.lang.String getDefaultSmsPackage(android.content.Context); field public static final android.net.Uri CONTENT_URI; @@ -40148,8 +40169,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"; } @@ -40174,6 +40197,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); @@ -40185,7 +40227,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); } @@ -40212,6 +40255,15 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); + method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); + } + + public final class SaveRequest implements android.os.Parcelable { + 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; } } @@ -40395,7 +40447,6 @@ package android.service.media { method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle); method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>); - method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; } @@ -40503,16 +40554,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String); - method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); + method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -40529,7 +40580,7 @@ package android.service.notification { method public final void snoozeNotification(java.lang.String, java.lang.String); method public final void snoozeNotification(java.lang.String, long); method public void unregisterAsSystemService() throws android.os.RemoteException; - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 @@ -40989,10 +41040,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(); @@ -44415,7 +44468,6 @@ package android.test.mock { method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException; method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException; method public android.content.ComponentName startService(android.content.Intent); - method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification); method public boolean stopService(android.content.Intent); method public void unbindService(android.content.ServiceConnection); method public void unregisterReceiver(android.content.BroadcastReceiver); @@ -44517,6 +44569,7 @@ package android.test.mock { method public byte[] getInstantAppCookie(); method public int getInstantAppCookieMaxSize(); method public android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String); + method public android.content.ComponentName getInstantAppInstallerComponent(); method public android.content.ComponentName getInstantAppResolverSettingsComponent(); method public java.util.List<android.content.pm.InstantAppInfo> getInstantApps(); method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -48945,7 +48998,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(); @@ -49034,7 +49086,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(); @@ -49267,7 +49318,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); @@ -49423,9 +49473,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 @@ -49993,7 +50040,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); @@ -51383,7 +51429,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 { @@ -53622,6 +53668,7 @@ package android.widget { method public java.lang.String getFormat(); method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener(); method public boolean isCountDown(); + method public boolean isTheFinalCountDown(); method public void setBase(long); method public void setCountDown(boolean); method public void setFormat(java.lang.String); @@ -59291,6 +59338,7 @@ package java.lang.invoke { method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>); method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...); method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType); + method public static java.lang.invoke.MethodHandle explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType); method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...); method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle); method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle); diff --git a/api/system-removed.txt b/api/system-removed.txt index bdcafae9b079..823d88faaece 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -5,10 +5,6 @@ package android.app { method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent); } - public static class Notification.Builder { - method public deprecated android.app.Notification.Builder chooseBadgeIcon(int); - } - public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable { method public deprecated void showAsNotification(android.content.Context); } @@ -24,6 +20,20 @@ package android.app.admin { } +package android.app.usage { + + public class StorageStatsManager { + method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException; + method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException; + method public deprecated boolean isQuotaSupported(java.lang.String); + method public deprecated android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public deprecated android.app.usage.StorageStats queryStatsForUid(java.lang.String, int) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + } + +} + package android.content { public abstract class Context { @@ -39,6 +49,10 @@ package android.content { package android.content.pm { + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { + field public deprecated java.lang.String volumeUuid; + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { field public deprecated boolean encryptionAware; } @@ -178,10 +192,14 @@ package android.os { package android.os.storage { public class StorageManager { - method public deprecated long getCacheQuotaBytes(); - method public deprecated long getCacheSizeBytes(); - method public deprecated long getExternalCacheQuotaBytes(); - method public deprecated long getExternalCacheSizeBytes(); + method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheSizeBytes() throws java.io.IOException; + method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException; method public android.os.storage.StorageVolume getPrimaryVolume(); method public android.os.storage.StorageVolume[] getVolumeList(); method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException; diff --git a/api/test-current.txt b/api/test-current.txt index 1fed00758057..88adb6ea642b 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(); @@ -3851,7 +3852,7 @@ package android.app { method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException; method public java.util.List<android.app.ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException; - method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; + method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException; method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException; method public int getUidImportance(int); method public deprecated boolean isInLockTaskMode(); @@ -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 @@ -5616,7 +5618,6 @@ package android.app { method public boolean removeAutomaticZenRule(java.lang.String); method public final void setInterruptionFilter(int); method public void setNotificationPolicy(android.app.NotificationManager.Policy); - method public deprecated android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification); method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule); field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED"; field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED"; @@ -6110,6 +6111,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 +6144,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 +6160,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 +6169,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 +6194,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 { @@ -6634,7 +6654,7 @@ package android.app.assist { public static class AssistStructure.ViewNode { method public float getAlpha(); - method public java.lang.String[] getAutoFillHints(); + method public java.lang.String[] getAutofillHints(); method public android.view.autofill.AutofillId getAutofillId(); method public java.lang.String[] getAutofillOptions(); method public int getAutofillType(); @@ -6898,6 +6918,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.app.Service); + 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); @@ -6995,13 +7023,13 @@ package android.app.usage { } public class StorageStatsManager { - method public long getFreeBytes(java.lang.String); - method public long getTotalBytes(java.lang.String); - method public boolean isQuotaSupported(java.lang.String); - method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle); - method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int); - method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle); + method public long getFreeBytes(java.util.UUID) throws java.io.IOException; + method public long getTotalBytes(java.util.UUID) throws java.io.IOException; + method public boolean isQuotaSupported(java.util.UUID); + method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForPackage(java.util.UUID, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public android.app.usage.StorageStats queryStatsForUid(java.util.UUID, int) throws java.io.IOException; + method public android.app.usage.StorageStats queryStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException; } public final class UsageEvents implements android.os.Parcelable { @@ -8099,7 +8127,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 { @@ -8274,7 +8307,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); } @@ -8282,6 +8316,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"; } @@ -9357,7 +9393,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"; @@ -10217,12 +10252,12 @@ package android.content.pm { field public java.lang.String[] splitNames; field public java.lang.String[] splitPublicSourceDirs; field public java.lang.String[] splitSourceDirs; + field public java.util.UUID storageUuid; field public int targetSdkVersion; field public java.lang.String taskAffinity; field public int theme; field public int uiOptions; field public int uid; - field public java.lang.String volumeUuid; } public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator { @@ -10342,7 +10377,7 @@ package android.content.pm { public class LauncherApps { ctor public LauncherApps(android.content.Context); method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); - method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle); + method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent); method public java.util.List<android.os.UserHandle> getProfiles(); method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int); @@ -12575,6 +12610,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; @@ -21976,7 +22012,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(); @@ -22074,6 +22110,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); } @@ -22529,7 +22578,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(); @@ -22564,6 +22613,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); @@ -22789,69 +22844,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,8 +22881,8 @@ package android.media { method public android.media.MediaPlayer.DrmInfo getDrmInfo(); method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException; method public int getDuration(); - method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; - method public android.media.MediaMetricsSet getMetrics(); + method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException; + method public android.os.PersistableBundle getMetrics(); method public android.media.PlaybackParams getPlaybackParams(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method public android.media.SyncParams getSyncParams(); @@ -22903,7 +22895,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -22930,7 +22922,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); - method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); + method public void setOnDrmConfigHelper(android.media.MediaPlayer.OnDrmConfigHelper); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -22971,6 +22963,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2 + field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 field public static final int SEEK_CLOSEST = 3; // 0x3 field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 field public static final int SEEK_NEXT_SYNC = 1; // 0x1 @@ -22980,11 +22976,25 @@ package android.media { } public static final class MediaPlayer.DrmInfo { - method public java.lang.String[] getMimes(); method public java.util.Map<java.util.UUID, byte[]> getPssh(); method public java.util.UUID[] getSupportedSchemes(); } + 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); } @@ -22997,7 +23007,7 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract interface MediaPlayer.OnDrmConfigListener { + public static abstract interface MediaPlayer.OnDrmConfigHelper { method public abstract void onDrmConfig(android.media.MediaPlayer); } @@ -23006,7 +23016,7 @@ package android.media { } public static abstract interface MediaPlayer.OnDrmPreparedListener { - method public abstract void onDrmPrepared(android.media.MediaPlayer, boolean); + method public abstract void onDrmPrepared(android.media.MediaPlayer, int); } public static abstract interface MediaPlayer.OnErrorListener { @@ -23037,8 +23047,12 @@ package android.media { method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int); } - public static final class MediaPlayer.ProvisioningErrorException extends android.media.MediaDrmException { - ctor public MediaPlayer.ProvisioningErrorException(java.lang.String); + public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String); + } + + public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException { + ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String); } public static class MediaPlayer.TrackInfo implements android.os.Parcelable { @@ -23059,7 +23073,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; @@ -23078,11 +23092,12 @@ package android.media { method public void setMaxDuration(int) throws java.lang.IllegalArgumentException; method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException; method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalStateException; - method public void setNextOutputFile(java.lang.String) throws java.io.IOException, java.lang.IllegalStateException; + method public void setNextOutputFile(java.io.File) throws java.io.IOException, java.lang.IllegalStateException; method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener); method public void setOnInfoListener(android.media.MediaRecorder.OnInfoListener); method public void setOrientationHint(int); method public void setOutputFile(java.io.FileDescriptor) throws java.lang.IllegalStateException; + method public void setOutputFile(java.io.File); method public void setOutputFile(java.lang.String) throws java.lang.IllegalStateException; method public void setOutputFormat(int) throws java.lang.IllegalStateException; method public void setPreviewDisplay(android.view.Surface); @@ -23127,6 +23142,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); } @@ -24090,7 +24124,6 @@ package android.media.browse { method public android.content.ComponentName getServiceComponent(); method public android.media.session.MediaSession.Token getSessionToken(); method public boolean isConnected(); - method public void search(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SearchCallback); method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback); method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback); method public void unsubscribe(java.lang.String); @@ -24126,12 +24159,6 @@ package android.media.browse { field public static final int FLAG_PLAYABLE = 2; // 0x2 } - public static abstract class MediaBrowser.SearchCallback { - ctor public MediaBrowser.SearchCallback(); - method public void onError(java.lang.String, android.os.Bundle); - method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.media.browse.MediaBrowser.MediaItem>); - } - public static abstract class MediaBrowser.SubscriptionCallback { ctor public MediaBrowser.SubscriptionCallback(); method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>); @@ -24340,8 +24367,6 @@ package android.media.session { public final class MediaController { ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token); - method public void addQueueItem(android.media.MediaDescription); - method public void addQueueItem(android.media.MediaDescription, int); method public void adjustVolume(int, int); method public boolean dispatchMediaButtonEvent(android.view.KeyEvent); method public android.os.Bundle getExtras(); @@ -24353,15 +24378,11 @@ package android.media.session { method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue(); method public java.lang.CharSequence getQueueTitle(); method public int getRatingType(); - method public int getRepeatMode(); method public android.app.PendingIntent getSessionActivity(); method public android.media.session.MediaSession.Token getSessionToken(); method public android.media.session.MediaController.TransportControls getTransportControls(); - method public boolean isShuffleModeEnabled(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); - method public void removeQueueItem(android.media.MediaDescription); - method public void removeQueueItemAt(int); method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void setVolumeTo(int, int); method public void unregisterCallback(android.media.session.MediaController.Callback); @@ -24375,10 +24396,8 @@ package android.media.session { method public void onPlaybackStateChanged(android.media.session.PlaybackState); method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>); method public void onQueueTitleChanged(java.lang.CharSequence); - method public void onRepeatModeChanged(int); method public void onSessionDestroyed(); method public void onSessionEvent(java.lang.String, android.os.Bundle); - method public void onShuffleModeChanged(boolean); } public static final class MediaController.PlaybackInfo { @@ -24407,8 +24426,6 @@ package android.media.session { method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle); method public void sendCustomAction(java.lang.String, android.os.Bundle); method public void setRating(android.media.Rating); - method public void setRepeatMode(int); - method public void setShuffleModeEnabled(boolean); method public void skipToNext(); method public void skipToPrevious(); method public void skipToQueueItem(long); @@ -24435,18 +24452,13 @@ package android.media.session { method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>); method public void setQueueTitle(java.lang.CharSequence); method public void setRatingType(int); - method public void setRepeatMode(int); method public void setSessionActivity(android.app.PendingIntent); - method public void setShuffleModeEnabled(boolean); field public static final deprecated int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 - field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4 field public static final deprecated int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } public static abstract class MediaSession.Callback { ctor public MediaSession.Callback(); - method public void onAddQueueItem(android.media.MediaDescription); - method public void onAddQueueItem(android.media.MediaDescription, int); method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void onCustomAction(java.lang.String, android.os.Bundle); method public void onFastForward(); @@ -24460,13 +24472,9 @@ package android.media.session { method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle); method public void onPrepareFromSearch(java.lang.String, android.os.Bundle); method public void onPrepareFromUri(android.net.Uri, android.os.Bundle); - method public void onRemoveQueueItem(android.media.MediaDescription); - method public void onRemoveQueueItemAt(int); method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); - method public void onSetRepeatMode(int); - method public void onSetShuffleModeEnabled(boolean); method public void onSkipToNext(); method public void onSkipToPrevious(); method public void onSkipToQueueItem(long); @@ -24527,17 +24535,12 @@ package android.media.session { field public static final long ACTION_REWIND = 8L; // 0x8L field public static final long ACTION_SEEK_TO = 256L; // 0x100L field public static final long ACTION_SET_RATING = 128L; // 0x80L - field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L - field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L field public static final long ACTION_STOP = 1L; // 0x1L field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR; field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL - field public static final int REPEAT_MODE_ALL = 2; // 0x2 - field public static final int REPEAT_MODE_NONE = 0; // 0x0 - field public static final int REPEAT_MODE_ONE = 1; // 0x1 field public static final int STATE_BUFFERING = 6; // 0x6 field public static final int STATE_CONNECTING = 8; // 0x8 field public static final int STATE_ERROR = 7; // 0x7 @@ -25886,6 +25889,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 { @@ -26858,8 +26865,8 @@ package android.net.wifi.aware { } public class DiscoverySession { - method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); - method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); method public void destroy(); method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]); } @@ -26945,8 +26952,8 @@ package android.net.wifi.aware { } public class WifiAwareSession { - method public java.lang.String createNetworkSpecifierOpen(int, byte[]); - method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); + method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); + method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String); method public void destroy(); method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); @@ -30877,6 +30884,7 @@ package android.os { method public android.util.SizeF getSizeF(java.lang.String); method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String); method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String); + method public java.util.UUID getUuid(java.lang.String); method public boolean hasFileDescriptors(); method public void putAll(android.os.Bundle); method public void putBinder(java.lang.String, android.os.IBinder); @@ -30901,6 +30909,7 @@ package android.os { method public void putSizeF(java.lang.String, android.util.SizeF); method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>); method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>); + method public void putUuid(java.lang.String, java.util.UUID); method public void readFromParcel(android.os.Parcel); method public void setClassLoader(java.lang.ClassLoader); method public void writeToParcel(android.os.Parcel, int); @@ -31451,6 +31460,7 @@ package android.os { method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>); + method public final java.util.UUID readUuid(); method public final java.lang.Object readValue(java.lang.ClassLoader); method public final void recycle(); method public final void setDataCapacity(int); @@ -31496,6 +31506,7 @@ package android.os { method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int); method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); method public final <T extends android.os.Parcelable> void writeTypedObject(T, int); + method public final void writeUuid(java.util.UUID); method public final void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -32130,15 +32141,16 @@ package android.os.storage { } public class StorageManager { - method public void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException; method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException; - method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException; - method public long getCacheQuotaBytes(java.io.File); - method public long getCacheSizeBytes(java.io.File); + method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException; + method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException; + method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException; method public java.lang.String getMountedObbPath(java.lang.String); method public android.os.storage.StorageVolume getPrimaryStorageVolume(); method public android.os.storage.StorageVolume getStorageVolume(java.io.File); method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes(); + method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException; method public boolean isEncrypted(java.io.File); @@ -32150,7 +32162,10 @@ package android.os.storage { method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException; method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener); field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; + field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID"; field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final java.util.UUID UUID_DEFAULT; } public final class StorageVolume implements android.os.Parcelable { @@ -35595,6 +35610,16 @@ package android.provider { field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id"; } + public static final class Telephony.ServiceStateTable { + method public static android.net.Uri getUriForSubId(int); + method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String); + field public static final java.lang.String AUTHORITY = "service-state"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + field public static final java.lang.String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + field public static final java.lang.String VOICE_REG_STATE = "voice_reg_state"; + } + public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns { method public static java.lang.String getDefaultSmsPackage(android.content.Context); field public static final android.net.Uri CONTENT_URI; @@ -37185,8 +37210,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"; } @@ -37211,6 +37238,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); @@ -37222,7 +37268,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); } @@ -37249,6 +37296,15 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]); + method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean); + } + + public final class SaveRequest implements android.os.Parcelable { + 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; } } @@ -37432,7 +37488,6 @@ package android.service.media { method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle); method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>); - method public void onSearch(java.lang.String, android.os.Bundle, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>); method public void setSessionToken(android.media.session.MediaSession.Token); field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; } @@ -37538,16 +37593,16 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String); - method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); + method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String, android.os.UserHandle); + method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String, android.os.UserHandle); method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); method public void onListenerDisconnected(); method public void onListenerHintsChanged(int); - method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int); - method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int); + method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int); + method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int); method public void onNotificationPosted(android.service.notification.StatusBarNotification); method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); @@ -37561,7 +37616,7 @@ package android.service.notification { method public final void setNotificationsShown(java.lang.String[]); method public final void snoozeNotification(java.lang.String, java.lang.String); method public final void snoozeNotification(java.lang.String, long); - method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel); field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4 field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2 @@ -37925,10 +37980,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(); @@ -39603,6 +39660,8 @@ package android.telecom { field public static final java.lang.String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT"; field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED"; field public static final deprecated java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL"; + field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED"; + field public static final java.lang.String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED"; field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS"; field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS"; field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION"; @@ -41048,7 +41107,6 @@ package android.test.mock { method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException; method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException; method public android.content.ComponentName startService(android.content.Intent); - method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification); method public boolean stopService(android.content.Intent); method public void unbindService(android.content.ServiceConnection); method public void unregisterReceiver(android.content.BroadcastReceiver); @@ -45731,7 +45789,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(); @@ -45820,7 +45877,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(); @@ -46056,7 +46112,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); @@ -46213,9 +46268,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 @@ -46787,7 +46839,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); @@ -48178,7 +48229,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 { @@ -50053,6 +50104,7 @@ package android.widget { method public java.lang.String getFormat(); method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener(); method public boolean isCountDown(); + method public boolean isTheFinalCountDown(); method public void setBase(long); method public void setCountDown(boolean); method public void setFormat(java.lang.String); @@ -55736,6 +55788,7 @@ package java.lang.invoke { method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>); method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...); method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType); + method public static java.lang.invoke.MethodHandle explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType); method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...); method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle); method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle); diff --git a/api/test-removed.txt b/api/test-removed.txt index 82705fd981f9..0f5b81abad4c 100644 --- a/api/test-removed.txt +++ b/api/test-removed.txt @@ -5,10 +5,6 @@ package android.app { method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent); } - public static class Notification.Builder { - method public deprecated android.app.Notification.Builder chooseBadgeIcon(int); - } - public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable { method public deprecated void showAsNotification(android.content.Context); } @@ -26,6 +22,20 @@ package android.app.admin { } +package android.app.usage { + + public class StorageStatsManager { + method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException; + method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException; + method public deprecated boolean isQuotaSupported(java.lang.String); + method public deprecated android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; + method public deprecated android.app.usage.StorageStats queryStatsForUid(java.lang.String, int) throws java.io.IOException; + method public deprecated android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException; + } + +} + package android.content { public abstract class Context { @@ -41,6 +51,10 @@ package android.content { package android.content.pm { + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { + field public deprecated java.lang.String volumeUuid; + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { field public deprecated boolean encryptionAware; } @@ -184,10 +198,14 @@ package android.os { package android.os.storage { public class StorageManager { - method public deprecated long getCacheQuotaBytes(); - method public deprecated long getCacheSizeBytes(); - method public deprecated long getExternalCacheQuotaBytes(); - method public deprecated long getExternalCacheSizeBytes(); + method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException; + method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException; + method public deprecated long getCacheSizeBytes() throws java.io.IOException; + method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException; + method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException; method public android.os.storage.StorageVolume getPrimaryVolume(); method public android.os.storage.StorageVolume[] getVolumeList(); method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException; diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp index 67874a8b9c02..d69dd79555a1 100644 --- a/cmds/idmap/scan.cpp +++ b/cmds/idmap/scan.cpp @@ -10,6 +10,7 @@ #include <androidfw/StreamingZipInflater.h> #include <androidfw/ZipFileRO.h> #include <cutils/jstring.h> +#include <cutils/properties.h> #include <private/android_filesystem_config.h> // for AID_SYSTEM #include <utils/SortedVector.h> #include <utils/String16.h> @@ -82,12 +83,26 @@ namespace { return String8(tmp); } + bool check_property(String16 property, String16 value) { + const char *prop; + const char *val; + + prop = strndup16to8(property.string(), property.size()); + char propBuf[PROPERTY_VALUE_MAX]; + property_get(prop, propBuf, NULL); + val = strndup16to8(value.string(), value.size()); + + return (strcmp(propBuf, val) == 0); + } + int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name, bool* is_static_overlay) { const size_t N = parser.getAttributeCount(); String16 target; int priority = -1; + String16 propName = String16(); + String16 propValue = String16(); for (size_t i = 0; i < N; ++i) { size_t len; String16 key(parser.getAttributeName(i, &len)); @@ -109,34 +124,32 @@ namespace { if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) { *is_static_overlay = (v.data != 0); } - } - } - if (target == String16(target_package_name)) { - return priority; - } - return NO_OVERLAY_TAG; - } - - String16 parse_package_name(const ResXMLTree& parser) - { - const size_t N = parser.getAttributeCount(); - String16 package_name; - for (size_t i = 0; i < N; ++i) { - size_t len; - String16 key(parser.getAttributeName(i, &len)); - if (key == String16("package")) { + } else if (key == String16("requiredSystemPropertyName")) { const char16_t *p = parser.getAttributeStringValue(i, &len); if (p != NULL) { - package_name = String16(p, len); + propName = String16(p, len); + } + } else if (key == String16("requiredSystemPropertyValue")) { + const char16_t *p = parser.getAttributeStringValue(i, &len); + if (p != NULL) { + propValue = String16(p, len); } } } - return package_name; - } - bool isValidStaticOverlayPackage(const String16& package_name) { - // TODO(b/35742444): Need to support selection method based on a package name. - return package_name.size() > 0; + // Note that conditional property enablement/exclusion only applies if + // the attribute is present. In its absence, all overlays are presumed enabled. + if (propName.size() > 0 && propValue.size() > 0) { + // if property set & equal to value, then include overlay - otherwise skip + if (!check_property(propName, propValue)) { + return NO_OVERLAY_TAG; + } + } + + if (target == String16(target_package_name)) { + return priority; + } + return NO_OVERLAY_TAG; } int parse_manifest(const void *data, size_t size, const char *target_package_name) @@ -149,7 +162,6 @@ namespace { } ResXMLParser::event_code_t type; - String16 package_name; bool is_static_overlay = false; int priority = NO_OVERLAY_TAG; do { @@ -157,16 +169,14 @@ namespace { if (type == ResXMLParser::START_TAG) { size_t len; String16 tag(parser.getElementName(&len)); - if (tag == String16("manifest")) { - package_name = parse_package_name(parser); - } else if (tag == String16("overlay")) { + if (tag == String16("overlay")) { priority = parse_overlay_tag(parser, target_package_name, &is_static_overlay); break; } } } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT); - if (is_static_overlay && isValidStaticOverlayPackage(package_name)) { + if (is_static_overlay) { return priority; } return NO_OVERLAY_TAG; diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java index 4be46540e19b..9df229cbf490 100644 --- a/cmds/media/src/com/android/commands/media/Media.java +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -228,16 +228,6 @@ public class Media extends BaseCommand { System.out.println("onVolumeInfoChanged " + info); } - @Override - public void onRepeatModeChanged(int repeatMode) throws RemoteException { - System.out.println("onRepeatModeChanged " + repeatMode); - } - - @Override - public void onShuffleModeChanged(boolean enabled) throws RemoteException { - System.out.println("onShuffleModeChanged " + enabled); - } - void printUsageMessage() { try { System.out.println("V2Monitoring session " + mController.getTag() diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 950991b75546..c4b7ed771b70 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -16,20 +16,16 @@ 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; import android.view.autofill.AutofillPopupWindow; -import android.view.autofill.AutofillValue; import android.view.autofill.IAutofillWindowPresenter; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ToolbarActionBar; import com.android.internal.app.WindowDecorActionBar; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; import com.android.internal.policy.PhoneWindow; import android.annotation.CallSuper; @@ -1233,6 +1229,13 @@ public class Activity extends ContextThemeWrapper mFragments.doLoaderStart(); getApplication().dispatchActivityStarted(this); + + if (mAutoFillResetNeeded) { + AutofillManager afm = getAutofillManager(); + if (afm != null) { + afm.onVisibleForAutofill(); + } + } } /** @@ -2067,6 +2070,7 @@ public class Activity extends ContextThemeWrapper if (args == null) { throw new IllegalArgumentException("Expected non-null picture-in-picture args"); } + updatePictureInPictureArgsForContentInsets(args); return ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken, args); } catch (RemoteException e) { return false; @@ -2084,11 +2088,27 @@ public class Activity extends ContextThemeWrapper if (args == null) { throw new IllegalArgumentException("Expected non-null picture-in-picture args"); } + updatePictureInPictureArgsForContentInsets(args); ActivityManagerNative.getDefault().setPictureInPictureArgs(mToken, args); } catch (RemoteException e) { } } + /** + * Updates the provided {@param args} with the last known content insets for this activity, to + * be used with the source hint rect for the transition into PiP. + */ + private void updatePictureInPictureArgsForContentInsets(PictureInPictureArgs args) { + if (args != null && args.hasSourceBoundsHint() && getWindow() != null && + getWindow().peekDecorView() != null && + getWindow().peekDecorView().getViewRootImpl() != null) { + args.setSourceRectHintInsets( + getWindow().peekDecorView().getViewRootImpl().getLastContentInsets()); + } else { + args.setSourceRectHintInsets(null); + } + } + void dispatchMovedToDisplay(int displayId, Configuration config) { updateDisplay(displayId); onMovedToDisplay(displayId, config); @@ -7406,6 +7426,54 @@ public class Activity extends ContextThemeWrapper return true; } + /** @hide */ + @Override + public boolean getViewVisibility(int viewId) { + Window window = getWindow(); + if (window == null) { + Log.i(TAG, "no window"); + return false; + } + + View decorView = window.peekDecorView(); + if (decorView == null) { + Log.i(TAG, "no decorView"); + return false; + } + + View view = decorView.findViewByAccessibilityIdTraversal(viewId); + if (view == null) { + Log.i(TAG, "cannot find view"); + return false; + } + + // Check if the view is visible by checking all parents + while (view != null) { + if (view == decorView) { + break; + } + + if (view.getVisibility() != View.VISIBLE) { + Log.i(TAG, view + " is not visible"); + return false; + } + + if (view.getParent() instanceof View) { + view = (View) view.getParent(); + } else { + break; + } + } + + return true; + } + + /** @hide */ + @Override + public boolean isVisibleForAutofill() { + return !mStopped; + } + /** * If set to true, this indicates to the system that it should never take a * screenshot of the activity to be used as a representation while it is not in a started state. @@ -7433,6 +7501,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..a4dcf630bc3e 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 @@ -2559,6 +2564,10 @@ public class ActivityManager { * <p><b>Note: this method is only intended for debugging or implementing * service management type user interfaces.</b></p> * + * @deprecated As of {@link android.os.Build.VERSION_CODES#O}, this method + * is no longer available to third party applications. For backwards compatibility, + * it will still return the caller's own services. + * * @param maxNum The maximum number of entries to return in the list. The * actual number returned may be smaller, depending on how many services * are running. @@ -2566,6 +2575,7 @@ public class ActivityManager { * @return Returns a list of RunningServiceInfo records describing each of * the running tasks. */ + @Deprecated public List<RunningServiceInfo> getRunningServices(int maxNum) throws SecurityException { try { @@ -3102,10 +3112,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 = 130; + 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 + */ + @Deprecated + public static final int IMPORTANCE_CANT_SAVE_STATE_DEPRECATED = 170; /** * Constant for {@link #importance}: This process is running an @@ -3113,7 +3145,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 +3181,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 +3208,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 +3459,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 +3479,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 +3529,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/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index a6838f8bbf0a..e07b7e4a03a1 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2639,4 +2639,13 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public ComponentName getInstantAppInstallerComponent() { + try { + return mPM.getInstantAppInstallerComponent(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 6cc8a14ea2f9..80de64b94519 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1447,21 +1447,13 @@ class ContextImpl extends Context { @Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); - return startServiceCommon(service, -1, null, false, mUser); + return startServiceCommon(service, false, mUser); } @Override public ComponentName startForegroundService(Intent service) { warnIfCallingFromSystemProcess(); - return startServiceCommon(service, -1, null, true, mUser); - } - - // STOPSHIP: remove when NotificationManager.startServiceInForeground() is retired - @Override - public ComponentName startServiceInForeground(Intent service, - int id, Notification notification) { - warnIfCallingFromSystemProcess(); - return startServiceCommon(service, id, notification, false, mUser); + return startServiceCommon(service, true, mUser); } @Override @@ -1472,29 +1464,22 @@ class ContextImpl extends Context { @Override public ComponentName startServiceAsUser(Intent service, UserHandle user) { - return startServiceCommon(service, -1, null, false, user); + return startServiceCommon(service, false, user); } @Override public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) { - return startServiceCommon(service, -1, null, true, user); + return startServiceCommon(service, true, user); } - // STOPSHIP: remove when NotificationManager.startServiceInForeground() is retired - @Override - public ComponentName startServiceInForegroundAsUser(Intent service, - int id, Notification notification, UserHandle user) { - return startServiceCommon(service, id, notification, false, user); - } - - private ComponentName startServiceCommon(Intent service, int id, Notification notification, - boolean requireForeground, UserHandle user) { + private ComponentName startServiceCommon(Intent service, boolean requireForeground, + UserHandle user) { try { validateServiceIntent(service); service.prepareToLeaveProcess(this); ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( - getContentResolver()), id, notification, requireForeground, + getContentResolver()), requireForeground, getOpPackageName(), user.getIdentifier()); if (cn != null) { if (cn.getPackageName().equals("!")) { diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index fc827a946a44..d2702440f839 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -129,8 +129,7 @@ interface IActivityManager { void finishSubActivity(in IBinder token, in String resultWho, int requestCode); PendingIntent getRunningServiceControlPanel(in ComponentName service); ComponentName startService(in IApplicationThread caller, in Intent service, - in String resolvedType, int id, in Notification notification, - boolean requireForeground, in String callingPackage, int userId); + in String resolvedType, boolean requireForeground, in String callingPackage, int userId); int stopService(in IApplicationThread caller, in Intent service, in String resolvedType, int userId); int bindService(in IApplicationThread caller, in IBinder token, in Intent service, @@ -632,6 +631,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/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index f4e8f3f5687e..cd9c095890e7 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.pm.ParceledListSlice; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import android.service.notification.Adjustment; import android.service.notification.Condition; import android.service.notification.IConditionListener; @@ -101,9 +102,9 @@ interface INotificationManager void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); void setInterruptionFilter(String pkg, int interruptionFilter); - void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in NotificationChannel channel); - ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg); - ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg); + void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user, in NotificationChannel channel); + ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user); + ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user); void applyEnqueuedAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 7f26f4fd7050..cab2114f6918 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2339,7 +2339,9 @@ public class Notification implements Parcelable @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("Notification(pri="); + sb.append("Notification(channel="); + sb.append(getChannel()); + sb.append(" pri="); sb.append(priority); sb.append(" contentView="); if (contentView != null) { @@ -2729,21 +2731,6 @@ public class Notification implements Parcelable } /** - * @removed - * Sets which icon to display as a badge for this notification. - * - * Must be one of {@link #BADGE_ICON_NONE}, {@link #BADGE_ICON_SMALL}, - * {@link #BADGE_ICON_LARGE}. - * - * Note: This value might be ignored, for launchers that don't support badge icons. - */ - @Deprecated - public Builder chooseBadgeIcon(int icon) { - mN.mBadgeIcon = icon; - return this; - } - - /** * Sets which icon to display as a badge for this notification. * * Must be one of {@link #BADGE_ICON_NONE}, {@link #BADGE_ICON_SMALL}, @@ -3259,9 +3246,10 @@ public class Notification implements Parcelable * This should only be used for high priority ongoing tasks like navigation, an ongoing * call, or other similarly high-priority events for the user. * <p> - * For most styles, the coloring will only be applied if the notification is ongoing. + * For most styles, the coloring will only be applied if the notification is for a + * foreground service notification. * However, for {@link MediaStyle} and {@link DecoratedMediaCustomViewStyle} notifications - * that have a media session attached there is no requirement for it to be ongoing. + * that have a media session attached there is no such requirement. * * @see Builder#setOngoing(boolean) * @see Builder#setColor(int) @@ -4214,9 +4202,22 @@ public class Notification implements Parcelable * @hide */ public RemoteViews makePublicContentView() { + return makePublicView(false /* ambient */); + } + + /** + * Construct a RemoteViews for the display in public contexts like on the lockscreen. + * + * @hide + */ + public RemoteViews makePublicAmbientNotification() { + return makePublicView(true /* ambient */); + } + + private RemoteViews makePublicView(boolean ambient) { if (mN.publicVersion != null) { final Builder builder = recoverBuilder(mContext, mN.publicVersion); - return builder.createContentView(); + return ambient ? builder.makeAmbientNotification() : builder.createContentView(); } Bundle savedBundle = mN.extras; Style style = mStyle; @@ -4233,14 +4234,15 @@ public class Notification implements Parcelable publicExtras.putBoolean(EXTRA_CHRONOMETER_COUNT_DOWN, savedBundle.getBoolean(EXTRA_CHRONOMETER_COUNT_DOWN)); publicExtras.putCharSequence(EXTRA_TITLE, - mContext.getString(R.string.notification_hidden_text)); + mContext.getString(com.android.internal.R.string.notification_hidden_text)); mN.extras = publicExtras; - final RemoteViews publicView = applyStandardTemplate(getBaseLayoutResource()); + final RemoteViews view = ambient ? makeAmbientNotification() + : applyStandardTemplate(getBaseLayoutResource()); mN.extras = savedBundle; mN.mLargeIcon = largeIcon; mN.largeIcon = largeIconLegacy; mStyle = style; - return publicView; + return view; } /** @@ -4759,12 +4761,10 @@ public class Notification implements Parcelable } /** - * @return whether this notification is ongoing and can't be dismissed by the user. + * @return whether this notification is a foreground service notification */ - private boolean isOngoing() { - final int ongoingFlags = Notification.FLAG_FOREGROUND_SERVICE - | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; - return (flags & ongoingFlags) != 0; + private boolean isForegroundService() { + return (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; } /** @@ -4789,8 +4789,7 @@ public class Notification implements Parcelable } /** - * @return true if this notification is colorized. This also factors in whether the - * notification is ongoing. + * @return true if this notification is colorized. * * @hide */ @@ -4806,7 +4805,7 @@ public class Notification implements Parcelable return true; } } - return extras.getBoolean(EXTRA_COLORIZED) && isOngoing(); + return extras.getBoolean(EXTRA_COLORIZED) && isForegroundService(); } private boolean hasLargeIcon() { diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 72c59781ae80..242d4a5e6267 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -1155,40 +1155,4 @@ public class NotificationManager } } - /** - * Start a service directly into the "foreground service" state. Unlike - * {@link android.content.Context#startService(Intent)}, this method - * can be used from within background operations like broadcast receivers - * or scheduled jobs. - * - * @param service Description of the service to be started. The Intent must be either - * fully explicit (supplying a component name) or specify a specific package - * name it is targeted to. - * @param id The identifier for this notification as per - * {@link #notify(int, Notification) NotificationManager.notify(int, Notification)}; - * must not be 0. - * @param notification The Notification to be displayed. - * @return If the service is being started or is already running, the - * {@link ComponentName} of the actual service that was started is - * returned; else if the service does not exist null is returned. - * - * @deprecated STOPSHIP transition away from this for O - */ - @Nullable - @Deprecated - public ComponentName startServiceInForeground(Intent service, - int id, Notification notification) { - return mContext.startServiceInForeground(service, id, notification); - } - - /** - * @hide like {@link #startServiceInForeground(Intent, int, Notification)} - * but for a specific user. - */ - @Nullable - public ComponentName startServiceInForegroundAsUser(Intent service, - int id, Notification notification, UserHandle user) { - return mContext.startServiceInForegroundAsUser(service, id, notification, user); - } - } diff --git a/core/java/android/app/PictureInPictureArgs.java b/core/java/android/app/PictureInPictureArgs.java index 0ce5eebed287..2fa636046901 100644 --- a/core/java/android/app/PictureInPictureArgs.java +++ b/core/java/android/app/PictureInPictureArgs.java @@ -49,6 +49,13 @@ public final class PictureInPictureArgs implements Parcelable { @Nullable private Rect mSourceRectHint; + /** + * The content insets that are used with the source hint rect for the transition into PiP where + * the insets are removed at the beginning of the transition. + */ + @Nullable + private Rect mSourceRectHintInsets; + PictureInPictureArgs(Parcel in) { if (in.readInt() != 0) { mAspectRatio = in.readFloat(); @@ -60,6 +67,9 @@ public final class PictureInPictureArgs implements Parcelable { if (in.readInt() != 0) { mSourceRectHint = Rect.CREATOR.createFromParcel(in); } + if (in.readInt() != 0) { + mSourceRectHintInsets = Rect.CREATOR.createFromParcel(in); + } } /** @@ -94,6 +104,9 @@ public final class PictureInPictureArgs implements Parcelable { if (otherArgs.hasSourceBoundsHint()) { mSourceRectHint = new Rect(otherArgs.getSourceRectHint()); } + if (otherArgs.hasSourceBoundsHintInsets()) { + mSourceRectHintInsets = new Rect(otherArgs.getSourceRectHintInsets()); + } } /** @@ -167,7 +180,19 @@ public final class PictureInPictureArgs implements Parcelable { } /** - * @return the launch bounds + * Sets the insets to be used with the source rect hint bounds. + * @hide + */ + public void setSourceRectHintInsets(Rect insets) { + if (insets == null) { + mSourceRectHintInsets = null; + } else { + mSourceRectHintInsets = new Rect(insets); + } + } + + /** + * @return the source rect hint * @hide */ public Rect getSourceRectHint() { @@ -175,6 +200,14 @@ public final class PictureInPictureArgs implements Parcelable { } /** + * @return the source rect hint insets. + * @hide + */ + public Rect getSourceRectHintInsets() { + return mSourceRectHintInsets; + } + + /** * @return whether there are launch bounds set * @hide */ @@ -182,12 +215,23 @@ public final class PictureInPictureArgs implements Parcelable { return mSourceRectHint != null && !mSourceRectHint.isEmpty(); } + /** + * @return whether there are source rect hint insets set + * @hide + */ + public boolean hasSourceBoundsHintInsets() { + return mSourceRectHintInsets != null; + } + @Override public PictureInPictureArgs clone() { PictureInPictureArgs args = new PictureInPictureArgs(mAspectRatio, mUserActions); if (mSourceRectHint != null) { args.setSourceRectHint(mSourceRectHint); } + if (mSourceRectHintInsets != null) { + args.setSourceRectHintInsets(mSourceRectHintInsets); + } return args; } @@ -216,6 +260,12 @@ public final class PictureInPictureArgs implements Parcelable { } else { out.writeInt(0); } + if (mSourceRectHintInsets != null) { + out.writeInt(1); + mSourceRectHintInsets.writeToParcel(out, 0); + } else { + out.writeInt(0); + } } public static final Creator<PictureInPictureArgs> CREATOR = diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 3191eec03ffa..6f326de76150 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -112,13 +112,6 @@ public class ResourcesManager { private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>> mAdjustedDisplays = new ArrayMap<>(); - /** - * A cache of DisplayId, Resources to Display. These display adjustments associated with these - * {@link Display}s will change as the resources change. - */ - private final ArrayMap<Pair<Integer, ResourcesKey>, WeakReference<Display>> mResourceDisplays = - new ArrayMap<>(); - public static ResourcesManager getInstance() { synchronized (ResourcesManager.class) { if (sResourcesManager == null) { @@ -251,51 +244,16 @@ public class ResourcesManager { */ public Display getAdjustedDisplay(final int displayId, Resources resources) { synchronized (this) { - // Note that the ResourcesKey might be {@code null} in the case that the - // {@link Resources} is actually from {@link Resources#getSystem}. In this case, it is - // not managed by {@link ResourcesManager}, but we still want to cache the display - // object. - final Pair<Integer, ResourcesKey> key = Pair.create(displayId, - findKeyForResourceImplLocked(resources.getImpl())); - - WeakReference<Display> wd = mResourceDisplays.get(key); - if (wd != null) { - final Display display = wd.get(); - if (display != null) { - return display; - } - } final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); if (dm == null) { // may be null early in system startup return null; } - final Display display = dm.getCompatibleDisplay(displayId, resources); - if (display != null) { - mResourceDisplays.put(key, new WeakReference<>(display)); - } - return display; + return dm.getCompatibleDisplay(displayId, resources); } } private void cleanupResourceImpl(ResourcesKey removedKey) { - // Remove any resource to display mapping based on this key. - final Iterator<Map.Entry<Pair<Integer, ResourcesKey>, WeakReference<Display>>> iter = - mResourceDisplays.entrySet().iterator(); - while (iter.hasNext()) { - final Map.Entry<Pair<Integer, ResourcesKey>, WeakReference<Display>> entry = - iter.next(); - final ResourcesKey key = entry.getKey().second; - - // Do not touch system resource displays (indicated by a {@code null} key) or - // non-matching keys. - if (key == null || !key.equals(removedKey)) { - continue; - } - - iter.remove(); - } - // Remove resource key to resource impl mapping and flush cache final ResourcesImpl res = mResourceImpls.remove(removedKey).get(); @@ -887,7 +845,6 @@ public class ResourcesManager { int changes = mResConfiguration.updateFrom(config); // Things might have changed in display manager, so clear the cached displays. mAdjustedDisplays.clear(); - mResourceDisplays.clear(); DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); 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/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 545aef5224b7..9f911f5c19c3 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -964,6 +964,16 @@ public class AssistStructure implements Parcelable { * * @return The hints for this view */ + @Nullable public String[] getAutofillHints() { + return mAutofillHints; + } + + /** + * @hide + * @deprecated use getAutofillHints() instead. + */ + // TODO(b/33197203): remove once clients don't use it anymore... + @Deprecated @Nullable public String[] getAutoFillHints() { return mAutofillHints; } diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java index 016a0fa8b92b..673d1b886b25 100644 --- a/core/java/android/app/job/JobParameters.java +++ b/core/java/android/app/job/JobParameters.java @@ -164,6 +164,20 @@ public class JobParameters implements Parcelable { * you should not call {@link JobService#jobFinished(JobParameters, boolean)} yourself * (otherwise you risk losing an upcoming JobWorkItem that is being enqueued at the same time). * + * <p>Once you are done with the {@link JobWorkItem} returned by this method, you must call + * {@link #completeWork(JobWorkItem)} with it to inform the system that you are done + * executing the work. The job will not be finished until all dequeued work has been + * completed. You do not, however, have to complete each returned work item before deqeueing + * the next one -- you can use {@link #dequeueWork()} multiple times before completing + * previous work if you want to process work in parallel, and you can complete the work + * in whatever order you want.</p> + * + * <p>If the job runs to the end of its available time period before all work has been + * completed, it will stop as normal. You should return true from + * {@link JobService#onStopJob(JobParameters)} in order to have the job rescheduled, and by + * doing so any pending as well as remaining uncompleted work will be re-queued + * for the next time the job runs.</p> + * * @return Returns a new {@link JobWorkItem} if there is one pending, otherwise null. * If null is returned, the system will also stop the job if all work has also been completed. * (This means that for correct operation, you must always call dequeueWork() after you have 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..a62861902a55 --- /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 Service mService; + + 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 service The {@link Service} that is creating this engine and in which it will run. + */ + public JobServiceEngine(Service service) { + mService = service; + mBinder = new JobInterface(this); + mHandler = new JobHandler(mService.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/app/job/JobWorkItem.java b/core/java/android/app/job/JobWorkItem.java index 4bb057e689b2..05687ee9aace 100644 --- a/core/java/android/app/job/JobWorkItem.java +++ b/core/java/android/app/job/JobWorkItem.java @@ -27,6 +27,7 @@ import android.os.Parcelable; final public class JobWorkItem implements Parcelable { final Intent mIntent; int mWorkId; + Object mGrants; /** * Create a new piece of work. @@ -57,6 +58,20 @@ final public class JobWorkItem implements Parcelable { return mWorkId; } + /** + * @hide + */ + public void setGrants(Object grants) { + mGrants = grants; + } + + /** + * @hide + */ + public Object getGrants() { + return mGrants; + } + public String toString() { return "JobWorkItem{id=" + mWorkId + " intent=" + mIntent + "}"; } diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java index 6fc4f5c1c95c..4b6479ad4a7b 100644 --- a/core/java/android/app/usage/StorageStatsManager.java +++ b/core/java/android/app/usage/StorageStatsManager.java @@ -16,17 +16,25 @@ package android.app.usage; +import static android.os.storage.StorageManager.convert; + +import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.WorkerThread; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.ParcelableException; import android.os.RemoteException; import android.os.UserHandle; +import android.os.storage.StorageManager; import com.android.internal.util.Preconditions; import java.io.File; +import java.io.IOException; +import java.util.UUID; /** * Provides access to detailed storage statistics. @@ -50,36 +58,49 @@ public class StorageStatsManager { /** {@hide} */ @TestApi - public boolean isQuotaSupported(String volumeUuid) { + public boolean isQuotaSupported(@NonNull UUID storageUuid) { try { - return mService.isQuotaSupported(volumeUuid, mContext.getOpPackageName()); + return mService.isQuotaSupported(convert(storageUuid), mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public boolean isQuotaSupported(String uuid) { + return isQuotaSupported(convert(uuid)); + } + /** - * Return the total space on the requested storage volume. + * Return the total size of the media hosting this storage volume. * <p> - * To reduce end user confusion, this value is the total storage size + * To reduce end user confusion, this value matches the total storage size * advertised in a retail environment, which is typically larger than the - * actual writable partition total size. - * <p> - * This method may take several seconds to calculate the requested values, - * so it should only be called from a worker thread. + * actual usable partition space. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. + * @throws IOException when the storage device isn't present. */ @WorkerThread - public long getTotalBytes(String volumeUuid) { + public long getTotalBytes(@NonNull UUID storageUuid) throws IOException { try { - return mService.getTotalBytes(volumeUuid, mContext.getOpPackageName()); + return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public long getTotalBytes(String uuid) throws IOException { + return getTotalBytes(convert(uuid)); + } + /** * Return the free space on the requested storage volume. * <p> @@ -90,18 +111,28 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. + * @throws IOException when the storage device isn't present. */ @WorkerThread - public long getFreeBytes(String volumeUuid) { + public long getFreeBytes(@NonNull UUID storageUuid) throws IOException { try { - return mService.getFreeBytes(volumeUuid, mContext.getOpPackageName()); + return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public long getFreeBytes(String uuid) throws IOException { + return getFreeBytes(convert(uuid)); + } + /** * Return storage statistics for a specific package on the requested storage * volume. @@ -112,27 +143,41 @@ public class StorageStatsManager { * Note: if the requested package uses the {@code android:sharedUserId} * manifest feature, this call will be forced into a slower manual * calculation path. If possible, consider always using - * {@link #queryStatsForUid(String, int)}, which is typically faster. + * {@link #queryStatsForUid(UUID, int)}, which is typically faster. * </p> * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. * @param packageName the package name you're interested in. * @param user the user you're interested in. - * @see ApplicationInfo#volumeUuid + * @throws PackageManager.NameNotFoundException when the requested package + * name isn't installed for the requested user. + * @throws IOException when the storage device isn't present. + * @see ApplicationInfo#storageUuid * @see PackageInfo#packageName */ @WorkerThread - public StorageStats queryStatsForPackage(String volumeUuid, String packageName, - UserHandle user) { + public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid, String packageName, + UserHandle user) throws PackageManager.NameNotFoundException, IOException { try { - return mService.queryStatsForPackage(volumeUuid, packageName, user.getIdentifier(), - mContext.getOpPackageName()); + return mService.queryStatsForPackage(convert(storageUuid), packageName, + user.getIdentifier(), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(PackageManager.NameNotFoundException.class); + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public StorageStats queryStatsForPackage(String uuid, String packageName, + UserHandle user) throws PackageManager.NameNotFoundException, IOException { + return queryStatsForPackage(convert(uuid), packageName, user); + } + /** * Return storage statistics for a specific UID on the requested storage * volume. @@ -140,21 +185,32 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. * @param uid the UID you're interested in. - * @see ApplicationInfo#volumeUuid + * @throws IOException when the storage device isn't present. + * @see ApplicationInfo#storageUuid * @see ApplicationInfo#uid */ @WorkerThread - public StorageStats queryStatsForUid(String volumeUuid, int uid) { + public StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid) throws IOException { try { - return mService.queryStatsForUid(volumeUuid, uid, mContext.getOpPackageName()); + return mService.queryStatsForUid(convert(storageUuid), uid, + mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public StorageStats queryStatsForUid(String uuid, int uid) throws IOException { + return queryStatsForUid(convert(uuid), uid); + } + /** * Return storage statistics for a specific {@link UserHandle} on the * requested storage volume. @@ -162,21 +218,32 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. * @param user the user you're interested in. + * @throws IOException when the storage device isn't present. * @see android.os.Process#myUserHandle() */ @WorkerThread - public StorageStats queryStatsForUser(String volumeUuid, UserHandle user) { + public StorageStats queryStatsForUser(@NonNull UUID storageUuid, UserHandle user) + throws IOException { try { - return mService.queryStatsForUser(volumeUuid, user.getIdentifier(), + return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException { + return queryStatsForUser(convert(uuid), user); + } + /** * Return shared/external storage statistics for a specific * {@link UserHandle} on the requested storage volume. @@ -184,20 +251,32 @@ public class StorageStatsManager { * This method may take several seconds to calculate the requested values, * so it should only be called from a worker thread. * - * @param volumeUuid the UUID of the storage volume you're interested in, or - * {@code null} to specify the default internal storage. + * @param storageUuid the UUID of the storage volume you're interested in, + * such as {@link StorageManager#UUID_DEFAULT}. + * @throws IOException when the storage device isn't present. * @see android.os.Process#myUserHandle() */ @WorkerThread - public ExternalStorageStats queryExternalStatsForUser(String volumeUuid, UserHandle user) { + public ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid, + UserHandle user) throws IOException { try { - return mService.queryExternalStatsForUser(volumeUuid, user.getIdentifier(), + return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(), mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user) + throws IOException { + return queryExternalStatsForUser(convert(uuid), user); + } + /** {@hide} */ public long getCacheQuotaBytes(String volumeUuid, int uid) { try { diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index ef3b1c50ffd3..624ec871a15a 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -498,8 +498,13 @@ public class AppWidgetHostView extends FrameLayout { private void updateContentDescription(AppWidgetProviderInfo info) { if (info != null) { LauncherApps launcherApps = getContext().getSystemService(LauncherApps.class); - ApplicationInfo appInfo = launcherApps.getApplicationInfo( - info.provider.getPackageName(), 0, info.getProfile()); + ApplicationInfo appInfo = null; + try { + appInfo = launcherApps.getApplicationInfo( + info.provider.getPackageName(), 0, info.getProfile()); + } catch (NameNotFoundException e) { + // ignore -- use null. + } if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0) { setContentDescription( 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/Context.java b/core/java/android/content/Context.java index 18120c714793..0adab1ad1752 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2647,18 +2647,6 @@ public abstract class Context { public abstract ComponentName startForegroundServiceAsUser(Intent service, UserHandle user); /** - * Start a service directly into the "foreground service" state. Unlike {@link #startService}, - * this method can be used from within background operations like broadcast receivers - * or scheduled jobs. The API entry point for this is in NotificationManager in order to - * preserve appropriate public package layering. - * @hide - * @deprecated STOPSHIP remove in favor of two-step startForegroundService() + startForeground() - */ - @Nullable - public abstract ComponentName startServiceInForeground(Intent service, - int id, Notification notification); - - /** * Request that a given application service be stopped. If the service is * not running, nothing happens. Otherwise it is stopped. Note that calls * to startService() are not counted -- this stops the service no matter @@ -2696,16 +2684,6 @@ public abstract class Context { public abstract ComponentName startServiceAsUser(Intent service, UserHandle user); /** - * @hide like {@link #startServiceInForeground(Intent, int, Notification)} - * but for a specific user. - * @deprecated STOPSHIP remove when trial API is turned off - */ - @Deprecated - @Nullable - public abstract ComponentName startServiceInForegroundAsUser(Intent service, - int id, Notification notification, UserHandle user); - - /** * @hide like {@link #stopService(Intent)} but for a specific user. */ public abstract boolean stopServiceAsUser(Intent service, UserHandle user); diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 53b021cbdf9f..b59fc3ddbb84 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -649,13 +649,6 @@ public class ContextWrapper extends Context { return mBase.startForegroundService(service); } - /** @hide STOPSHIP remove when trial API is turned down */ - @Override - public ComponentName startServiceInForeground(Intent service, - int id, Notification notification) { - return mBase.startServiceInForeground(service, id, notification); - } - @Override public boolean stopService(Intent name) { return mBase.stopService(name); @@ -673,13 +666,6 @@ public class ContextWrapper extends Context { return mBase.startForegroundServiceAsUser(service, user); } - /** @hide STOPSHIP removed when trial API is turned down */ - @Override - public ComponentName startServiceInForegroundAsUser(Intent service, - int id, Notification notification, UserHandle user) { - return mBase.startServiceInForegroundAsUser(service, id, notification, user); - } - /** @hide */ @Override public boolean stopServiceAsUser(Intent name, UserHandle user) { 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/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 23e54baab622..d64f018c3f2e 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -1787,7 +1787,7 @@ public class IntentFilter implements Parcelable { sb.append(", mHasPartialTypes="); sb.append(mHasPartialTypes); du.println(sb.toString()); } - { + if (getAutoVerify()) { sb.setLength(0); sb.append(prefix); sb.append("AutoVerify="); sb.append(getAutoVerify()); du.println(sb.toString()); diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 5f53e27eeb07..8b2809af5cb2 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -29,6 +29,7 @@ import android.os.Environment; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import android.os.storage.StorageManager; import android.text.TextUtils; import android.util.Printer; import android.util.SparseArray; @@ -41,6 +42,7 @@ import java.text.Collator; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; +import java.util.UUID; /** * Information you can retrieve about a particular application. This @@ -621,12 +623,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public float maxAspectRatio; + /** @removed */ + @Deprecated + public String volumeUuid; + /** * UUID of the storage volume on which this application is being hosted. For * apps hosted on the default internal storage at - * {@link Environment#getDataDirectory()}, the UUID value is {@code null}. + * {@link Environment#getDataDirectory()}, the UUID value is + * {@link StorageManager#UUID_DEFAULT}. */ - public String volumeUuid; + public UUID storageUuid; /** {@hide} */ public String scanSourceDir; @@ -1134,6 +1141,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { compatibleWidthLimitDp = orig.compatibleWidthLimitDp; largestWidthLimitDp = orig.largestWidthLimitDp; volumeUuid = orig.volumeUuid; + storageUuid = orig.storageUuid; scanSourceDir = orig.scanSourceDir; scanPublicSourceDir = orig.scanPublicSourceDir; sourceDir = orig.sourceDir; @@ -1195,7 +1203,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(requiresSmallestWidthDp); dest.writeInt(compatibleWidthLimitDp); dest.writeInt(largestWidthLimitDp); - dest.writeString(volumeUuid); + dest.writeUuid(storageUuid); dest.writeString(scanSourceDir); dest.writeString(scanPublicSourceDir); dest.writeString(sourceDir); @@ -1257,7 +1265,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { requiresSmallestWidthDp = source.readInt(); compatibleWidthLimitDp = source.readInt(); largestWidthLimitDp = source.readInt(); - volumeUuid = source.readString(); + storageUuid = source.readUuid(); + volumeUuid = StorageManager.convert(storageUuid); scanSourceDir = source.readString(); scanPublicSourceDir = source.readString(); sourceDir = source.readString(); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 147df763fce2..bbc942aff372 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -632,4 +632,6 @@ interface IPackageManager { void deletePreloadsFileCache(); ComponentName getInstantAppResolverSettingsComponent(); + + ComponentName getInstantAppInstallerComponent(); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index c3bdde51af0f..8ead0ec612f8 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -22,6 +22,8 @@ import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ActivityNotFoundException; import android.content.ComponentName; @@ -52,6 +54,8 @@ import android.os.UserManager; import android.util.DisplayMetrics; import android.util.Log; +import com.android.internal.util.Preconditions; + import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -612,11 +616,20 @@ public class LauncherApps { * null if the package isn't installed for the given user, or the target user * is not enabled. */ - public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, - UserHandle user) { + public ApplicationInfo getApplicationInfo(@NonNull String packageName, + @ApplicationInfoFlags int flags, @NonNull UserHandle user) + throws PackageManager.NameNotFoundException { + Preconditions.checkNotNull(packageName, "packageName"); + Preconditions.checkNotNull(packageName, "user"); logErrorForInvalidProfileAccess(user); try { - return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user); + final ApplicationInfo ai = mService + .getApplicationInfo(mContext.getPackageName(), packageName, flags, user); + if (ai == null) { + throw new NameNotFoundException("Package " + packageName + " not found for user " + + user.getIdentifier()); + } + return ai; } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -1268,15 +1281,34 @@ public class LauncherApps { * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent * respectively to the default launcher app. * - * <p>Note the launcher may receive a request to pin a shortcut that is already pinned, because - * the user may actually want to have multiple icons of the same shortcut on the launcher. - * The launcher can tell this case by calling {@link ShortcutInfo#isPinned()} on the shortcut - * returned by {@link #getShortcutInfo()}. In this case, calling {@link #accept()} is optional; - * even if the launcher does not call it, the shortcut is already pinned. Also in this case, - * the {@code options} argument to {@link #accept(Bundle)} will be ignored. + * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type. + * + * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a + * {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()}, + * or {@link #accept(Bundle)} with a null or empty Bundle. No options are defined for + * pin-shortcuts requests. + * + * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type. + * + * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in + * which case {@link ShortcutInfo#isPinned()} returns true. This means the user wants to create + * another pinned shortcut for a shortcut that's already pinned. If the launcher accepts it, + * {@link #accept()} must still be called even though the shortcut is already pinned, and + * create a new pinned shortcut icon for it. + * + * <p>See also {@link ShortcutManager} for more details. + * + * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type. + * + * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a + * an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with + * the appwidget integer ID set to the + * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra. + * + * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null + * {@link AppWidgetProviderInfo} for this type. * - * <p>For AppWidget pin requests launcher should send back the appwidget id as an extra for - * {@link #accept(Bundle)} as {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}. + * <p>See also {@link AppWidgetManager} for more details. * * @see #EXTRA_PIN_ITEM_REQUEST * @see #getPinItemRequest(Intent) @@ -1306,8 +1338,9 @@ public class LauncherApps { } /** - * Represents the type of a request. For now {@link #REQUEST_TYPE_SHORTCUT} is the only - * valid type. + * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants. + * + * @return one of the {@code REQUEST_TYPE_} constants. */ @RequestType public int getRequestType() { @@ -1315,8 +1348,12 @@ public class LauncherApps { } /** - * {@link ShortcutInfo} sent by the requesting app. Always non-null for a - * {@link #REQUEST_TYPE_SHORTCUT} request. + * {@link ShortcutInfo} sent by the requesting app. + * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a + * different request type. + * + * @return requested {@link ShortcutInfo} when a request is of the + * {@link #REQUEST_TYPE_SHORTCUT} type. Null otherwise. */ @Nullable public ShortcutInfo getShortcutInfo() { @@ -1328,8 +1365,12 @@ public class LauncherApps { } /** - * {@link AppWidgetProviderInfo} sent by the requesting app. Always non-null for a - * {@link #REQUEST_TYPE_APPWIDGET} request. + * {@link AppWidgetProviderInfo} sent by the requesting app. + * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a + * different request type. + * + * @return requested {@link AppWidgetProviderInfo} when a request is of the + * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise. */ @Nullable public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) { @@ -1347,6 +1388,11 @@ public class LauncherApps { /** * Any extras sent by the requesting app. + * + * @return For a shortcut request, this method always return null. For an AppWidget + * request, this method returns the extras passed to the + * {@link android.appwidget.AppWidgetManager#requestPinAppWidget( + * ComponentName, Bundle, PendingIntent)} API. See {@link AppWidgetManager} for details. */ @Nullable public Bundle getExtras() { @@ -1358,8 +1404,9 @@ public class LauncherApps { } /** - * Return {@code TRUE} if a request is valid -- i.e. {@link #accept(Bundle)} has not been - * called yet. + * Return whether a request is still valid. + * + * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called. */ public boolean isValid() { try { @@ -1371,6 +1418,12 @@ public class LauncherApps { /** * Called by the receiving launcher app when the user accepts the request. + * + * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request. + * + * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned. + * {@code FALSE} if the item hasn't been pinned, for example, because the request had + * already been canceled, in which case the launcher must not pin the requested item. */ public boolean accept(@Nullable Bundle options) { try { @@ -1381,7 +1434,11 @@ public class LauncherApps { } /** - * Same as as {@link #accept(Bundle)} with no options. + * Called by the receiving launcher app when the user accepts the request, with no options. + * + * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned. + * {@code FALSE} if the item hasn't been pinned, for example, because the request had + * already been canceled, in which case the launcher must not pin the requested item. */ public boolean accept() { return accept(/* options= */ null); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index e5c8f0d2ab3e..09906be7cd26 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -6275,9 +6275,19 @@ public abstract class PackageManager { * Return the {@link ComponentName} of the activity providing Settings for the Instant App * resolver. * - * @see {@link android.content.intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS} + * @see {@link android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS} * @hide */ @SystemApi public abstract ComponentName getInstantAppResolverSettingsComponent(); + + /** + * Return the {@link ComponentName} of the activity responsible for installing instant + * applications. + * + * @see {@link android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE} + * @hide + */ + @SystemApi + public abstract ComponentName getInstantAppInstallerComponent(); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 430d8b15216f..1f78bff9e1a7 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -64,8 +64,10 @@ import android.os.FileUtils; import android.os.Parcel; import android.os.Parcelable; import android.os.PatternMatcher; +import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.os.storage.StorageManager; import android.system.ErrnoException; import android.system.OsConstants; import android.system.StructStat; @@ -116,6 +118,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.ZipEntry; @@ -2111,6 +2114,12 @@ public class PackageParser { pkg.mIsStaticOverlay = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic, false); + final String propName = sa.getString( + com.android.internal.R.styleable + .AndroidManifestResourceOverlay_requiredSystemPropertyName); + final String propValue = sa.getString( + com.android.internal.R.styleable + .AndroidManifestResourceOverlay_requiredSystemPropertyValue); sa.recycle(); if (pkg.mOverlayTarget == null) { @@ -2118,15 +2127,22 @@ public class PackageParser { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } + if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { outError[0] = "<overlay> priority must be between 0 and 9999"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } - if (pkg.mIsStaticOverlay) { - // TODO(b/35742444): Need to support selection method based on a package name. + + // check to see if overlay should be excluded based on system property condition + if (!checkOverlayRequiredSystemProperty(propName, propValue)) { + Slog.i(TAG, "Skipping target and overlay pair " + pkg.mOverlayTarget + " and " + + pkg.baseCodePath+ ": overlay ignored due to required system property: " + + propName + " with value: " + propValue); + return null; } + XmlUtils.skipCurrentTag(parser); } else if (tagName.equals(TAG_KEY_SETS)) { @@ -2531,6 +2547,25 @@ public class PackageParser { return pkg; } + private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) { + + if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) { + if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) { + // malformed condition - incomplete + Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName + + "=" + propValue + "' - require both requiredSystemPropertyName" + + " AND requiredSystemPropertyValue to be specified."); + return false; + } + // no valid condition set - so no exclusion criteria, overlay will be included. + return true; + } + + // check property value - make sure it is both set and equal to expected value + final String currValue = SystemProperties.get(propName); + return (currValue != null && currValue.equals(propValue)); + } + /** * This is a pre-density application which will get scaled - instead of being pixel perfect. * This type of application is not resizable. @@ -5741,11 +5776,14 @@ public class PackageParser { } public void setApplicationVolumeUuid(String volumeUuid) { + final UUID storageUuid = StorageManager.convert(volumeUuid); this.applicationInfo.volumeUuid = volumeUuid; + this.applicationInfo.storageUuid = storageUuid; if (childPackages != null) { final int packageCount = childPackages.size(); for (int i = 0; i < packageCount; i++) { childPackages.get(i).applicationInfo.volumeUuid = volumeUuid; + childPackages.get(i).applicationInfo.storageUuid = storageUuid; } } } diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index e8e989f20ef7..f61032ef8250 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -290,7 +290,8 @@ public final class CameraManager { cameraId, callback, handler, - characteristics); + characteristics, + mContext.getApplicationInfo().targetSdkVersion); ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index e75b3758a31e..ab87f15d8794 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -36,6 +36,7 @@ import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.SubmitInfo; import android.hardware.camera2.utils.SurfaceUtils; import android.hardware.ICameraService; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -118,6 +119,8 @@ public class CameraDeviceImpl extends CameraDevice private CameraCaptureSessionCore mCurrentSession; private int mNextSessionId = 0; + private final int mAppTargetSdkVersion; + // Runnables for all state transitions, except error, which needs the // error code argument @@ -234,7 +237,7 @@ public class CameraDeviceImpl extends CameraDevice }; public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler, - CameraCharacteristics characteristics) { + CameraCharacteristics characteristics, int appTargetSdkVersion) { if (cameraId == null || callback == null || handler == null || characteristics == null) { throw new IllegalArgumentException("Null argument given"); } @@ -242,6 +245,7 @@ public class CameraDeviceImpl extends CameraDevice mDeviceCallback = callback; mDeviceHandler = handler; mCharacteristics = characteristics; + mAppTargetSdkVersion = appTargetSdkVersion; final int MAX_TAG_LEN = 23; String tag = String.format("CameraDevice-JV-%s", mCameraId); @@ -671,6 +675,16 @@ public class CameraDeviceImpl extends CameraDevice } } + private void overrideEnableZsl(CameraMetadataNative request, boolean newValue) { + Boolean enableZsl = request.get(CaptureRequest.CONTROL_ENABLE_ZSL); + if (enableZsl == null) { + // If enableZsl is not available, don't override. + return; + } + + request.set(CaptureRequest.CONTROL_ENABLE_ZSL, newValue); + } + @Override public CaptureRequest.Builder createCaptureRequest(int templateType) throws CameraAccessException { @@ -681,6 +695,13 @@ public class CameraDeviceImpl extends CameraDevice templatedRequest = mRemoteDevice.createDefaultRequest(templateType); + // If app target SDK is older than O, or it's not a still capture template, enableZsl + // must be false in the default request. + if (mAppTargetSdkVersion < Build.VERSION_CODES.O || + templateType != TEMPLATE_STILL_CAPTURE) { + overrideEnableZsl(templatedRequest, false); + } + CaptureRequest.Builder builder = new CaptureRequest.Builder( templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java index 04482210c088..a76a8a0e3da2 100644 --- a/core/java/android/metrics/LogMaker.java +++ b/core/java/android/metrics/LogMaker.java @@ -94,6 +94,16 @@ public class LogMaker { } /** + * Set event latency. + * + * @hide // TODO Expose in the future? Too late for O. + */ + public LogMaker setLatency(long milliseconds) { + entries.put(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, milliseconds); + return this; + } + + /** * This will be set by the system when the log is persisted. * Client-supplied values will be ignored. * 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/os/Bundle.java b/core/java/android/os/Bundle.java index 9b5ff29d592e..167c46d6ded0 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -25,6 +25,7 @@ import android.util.SparseArray; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * A mapping from String keys to various {@link Parcelable} values. @@ -476,6 +477,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Inserts a UUID value into the mapping of this Bundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a UUID object, or null + */ + public void putUuid(@Nullable String key, @Nullable UUID value) { + unparcel(); + mMap.put(key, value); + } + + /** * Inserts an array of Parcelable values into the mapping of this Bundle, * replacing any existing value for the given key. Either key or value may * be null. @@ -858,6 +871,26 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * value is explicitly associated with the key. * * @param key a String, or null + * @return a UUID value, or null + */ + @Nullable + public UUID getUuid(@Nullable String key) { + unparcel(); + final Object o = mMap.get(key); + try { + return (UUID) o; + } catch (ClassCastException e) { + typeWarning(key, o, "UUID", e); + return null; + } + } + + /** + * Returns the value associated with the given key, or null if + * no mapping of the desired type exists for the given key or a null + * value is explicitly associated with the key. + * + * @param key a String, or null * @return a Bundle value, or null */ @Nullable diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index c3836a38c822..c1647c74f363 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -16,8 +16,6 @@ package android.os; -import android.annotation.IntegerRes; -import android.annotation.NonNull; import android.annotation.Nullable; import android.text.TextUtils; import android.util.ArrayMap; @@ -29,6 +27,9 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; +import dalvik.annotation.optimization.FastNative; +import dalvik.system.VMRuntime; + import libcore.util.SneakyThrow; import java.io.ByteArrayInputStream; @@ -49,9 +50,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; - -import dalvik.annotation.optimization.FastNative; -import dalvik.system.VMRuntime; +import java.util.UUID; /** * Container for a message (data and object references) that can @@ -243,6 +242,7 @@ public final class Parcel { private static final int VAL_SIZE = 26; private static final int VAL_SIZEF = 27; private static final int VAL_DOUBLEARRAY = 28; + private static final int VAL_UUID = 29; // The initial int32 in a Binder call's reply Parcel header: // Keep these in sync with libbinder's binder/Status.h. @@ -831,6 +831,15 @@ public final class Parcel { } /** + * Flatten a UUID into the parcel at the current dataPosition(), + * growing dataCapacity() if needed. + */ + public final void writeUuid(UUID val) { + writeLong(val.getMostSignificantBits()); + writeLong(val.getLeastSignificantBits()); + } + + /** * Flatten a List into the parcel at the current dataPosition(), growing * dataCapacity() if needed. The List values are written using * {@link #writeValue} and must follow the specification there. @@ -1678,6 +1687,9 @@ public final class Parcel { } else if (v instanceof double[]) { writeInt(VAL_DOUBLEARRAY); writeDoubleArray((double[]) v); + } else if (v instanceof UUID) { + writeInt(VAL_UUID); + writeUuid((UUID) v); } else { Class<?> clazz = v.getClass(); if (clazz.isArray() && clazz.getComponentType() == Object.class) { @@ -2182,6 +2194,13 @@ public final class Parcel { } /** + * Read a UUID from the parcel at the current dataPosition(). + */ + public final UUID readUuid() { + return new UUID(readLong(), readLong()); + } + + /** * Read and return a byte[] object from the parcel. */ public final byte[] createByteArray() { @@ -2731,6 +2750,9 @@ public final class Parcel { case VAL_DOUBLEARRAY: return createDoubleArray(); + case VAL_UUID: + return readUuid(); + default: int off = dataPosition() - 4; throw new RuntimeException( diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index b5af766fd159..394253173553 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -66,6 +66,7 @@ import com.android.internal.util.Preconditions; import java.io.File; import java.io.FileDescriptor; +import java.io.FileNotFoundException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -77,6 +78,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; @@ -117,19 +119,66 @@ public class StorageManager { public static final String UUID_PRIVATE_INTERNAL = null; /** {@hide} */ public static final String UUID_PRIMARY_PHYSICAL = "primary_physical"; + /** {@hide} */ + public static final String UUID_SYSTEM = "system"; + // NOTE: UUID constants below are namespaced + // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default + // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical + // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system /** - * Activity Action: Allows the user to manage their storage. This activity provides the ability - * to free up space on the device by deleting data such as apps. + * UUID representing the default internal storage of this device which + * provides {@link Environment#getDataDirectory()}. * <p> - * Input: Nothing. + * This value is constant across all devices and it will never change, and + * thus it cannot be used to uniquely identify a particular physical device. + * + * @see #getUuidForPath(File) + */ + public static final UUID UUID_DEFAULT = UUID + .fromString("41217664-9172-527a-b3d5-edabb50a7d69"); + + /** {@hide} */ + public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID + .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd"); + + /** {@hide} */ + public static final UUID UUID_SYSTEM_ = UUID + .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0"); + + /** + * Activity Action: Allows the user to manage their storage. This activity + * provides the ability to free up space on the device by deleting data such + * as apps. * <p> - * Output: Nothing. + * If the sending application has a specific storage device or allocation + * size in mind, they can optionally define {@link #EXTRA_UUID} or + * {@link #EXTRA_REQUESTED_BYTES}, respectively. */ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_MANAGE_STORAGE - = "android.os.storage.action.MANAGE_STORAGE"; + public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; + + /** + * Extra {@link UUID} used to indicate the storage volume where an + * application is interested in allocating or managing disk space. + * + * @see #ACTION_MANAGE_STORAGE + * @see #UUID_DEFAULT + * @see #getUuidForPath(File) + */ + public static final String EXTRA_UUID = "android.os.storage.extra.UUID"; + + /** + * Extra used to indicate the total size (in bytes) that an application is + * interested in allocating. + * <p> + * When defined, the management UI will help guide the user to free up + * enough disk space to reach this requested value. + * + * @see #ACTION_MANAGE_STORAGE + */ + public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; /** {@hide} */ public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0; @@ -668,34 +717,44 @@ public class StorageManager { } } - /** {@hide} */ - public @Nullable String findUuidForPath(File path) { + /** + * Return a UUID identifying the storage volume that hosts the given + * filesystem path. + * <p> + * If this path is hosted by the default internal storage of the device at + * {@link Environment#getDataDirectory()}, the returned value will be + * {@link #UUID_DEFAULT}. + * + * @throws IOException when the storage device at the given path isn't + * present, or when it doesn't have a valid UUID. + */ + public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException { Preconditions.checkNotNull(path); final String pathString = path.getAbsolutePath(); if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) { - return StorageManager.UUID_PRIVATE_INTERNAL; + return UUID_DEFAULT; } try { for (VolumeInfo vol : mStorageManager.getVolumes(0)) { if (vol.path != null && FileUtils.contains(vol.path, pathString)) { // TODO: verify that emulated adopted devices have UUID of // underlying volume - return vol.fsUuid; + return convert(vol.fsUuid); } } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - throw new IllegalStateException("Failed to find a storage device for " + path); + throw new FileNotFoundException("Failed to find a storage device for " + path); } /** {@hide} */ - public @Nullable File findPathForUuid(String volumeUuid) { + public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException { final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid); if (vol != null) { return vol.getPath(); } - throw new IllegalStateException("Failed to find a storage device for " + volumeUuid); + throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid); } /** {@hide} */ @@ -1451,7 +1510,7 @@ public class StorageManager { /** * Return quota size in bytes for all cached data belonging to the calling - * app on the filesystem that hosts the given path. + * app on the given storage volume. * <p> * If your app goes above this quota, your cached files will be some of the * first to be deleted when additional disk space is needed. Conversely, if @@ -1466,21 +1525,34 @@ public class StorageManager { * as a single unit. * </p> * - * @see #getCacheSizeBytes(File) + * @param storageUuid the UUID of the storage volume that you're interested + * in. The UUID for a specific path can be obtained using + * {@link #getUuidForPath(File)}. + * @throws IOException when the storage device isn't present, or when it + * doesn't support cache quotas. + * @see #getCacheSizeBytes(UUID) */ - public long getCacheQuotaBytes(File path) { + public long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException { try { - final String volumeUuid = findUuidForPath(path); final ApplicationInfo app = mContext.getApplicationInfo(); - return mStorageManager.getCacheQuotaBytes(volumeUuid, app.uid); + return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** @removed */ + @Deprecated + public long getCacheQuotaBytes(@NonNull File path) throws IOException { + return getCacheQuotaBytes(getUuidForPath(path)); + } + /** * Return total size in bytes of all cached data belonging to the calling - * app on the filesystem that hosts the given path. + * app on the given storage volume. * <p> * Cached data tracked by this method always includes * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and @@ -1493,13 +1565,20 @@ public class StorageManager { * as a single unit. * </p> * - * @see #getCacheQuotaBytes() + * @param storageUuid the UUID of the storage volume that you're interested + * in. The UUID for a specific path can be obtained using + * {@link #getUuidForPath(File)}. + * @throws IOException when the storage device isn't present, or when it + * doesn't support cache quotas. + * @see #getCacheQuotaBytes(UUID) */ - public long getCacheSizeBytes(File path) { + public long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException { try { - final String volumeUuid = findUuidForPath(path); final ApplicationInfo app = mContext.getApplicationInfo(); - return mStorageManager.getCacheSizeBytes(volumeUuid, app.uid); + return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1507,25 +1586,31 @@ public class StorageManager { /** @removed */ @Deprecated - public long getCacheQuotaBytes() { + public long getCacheSizeBytes(@NonNull File path) throws IOException { + return getCacheSizeBytes(getUuidForPath(path)); + } + + /** @removed */ + @Deprecated + public long getCacheQuotaBytes() throws IOException { return getCacheQuotaBytes(mContext.getCacheDir()); } /** @removed */ @Deprecated - public long getCacheSizeBytes() { + public long getCacheSizeBytes() throws IOException { return getCacheSizeBytes(mContext.getCacheDir()); } /** @removed */ @Deprecated - public long getExternalCacheQuotaBytes() { + public long getExternalCacheQuotaBytes() throws IOException { return getCacheQuotaBytes(mContext.getExternalCacheDir()); } /** @removed */ @Deprecated - public long getExternalCacheSizeBytes() { + public long getExternalCacheSizeBytes() throws IOException { return getCacheSizeBytes(mContext.getExternalCacheDir()); } @@ -1542,8 +1627,8 @@ public class StorageManager { * this flag to take effect. * </p> * - * @see #getAllocatableBytes(File, int) - * @see #allocateBytes(File, long, int) + * @see #getAllocatableBytes(UUID, int) + * @see #allocateBytes(UUID, long, int) * @see #allocateBytes(FileDescriptor, long, int) */ @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) @@ -1558,32 +1643,43 @@ public class StorageManager { /** * Return the maximum number of new bytes that your app can allocate for - * itself using {@link #allocateBytes(File, long, int)} at the given path. - * This value is typically larger than {@link File#getUsableSpace()}, since - * the system may be willing to delete cached files to satisfy an allocation - * request. + * itself on the given storage volume. This value is typically larger than + * {@link File#getUsableSpace()}, since the system may be willing to delete + * cached files to satisfy an allocation request. You can then allocate + * space for yourself using {@link #allocateBytes(UUID, long, int)} or + * {@link #allocateBytes(FileDescriptor, long, int)}. * <p> * This method is best used as a pre-flight check, such as deciding if there * is enough space to store an entire music album before you allocate space * for each audio file in the album. Attempts to allocate disk space beyond * the returned value will fail. + * <p> + * If the returned value is not large enough for the data you'd like to + * store, you can launch {@link #ACTION_MANAGE_STORAGE} with the + * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help + * involve the user in freeing up disk space. * <p class="note"> * Note: if your app uses the {@code android:sharedUserId} manifest feature, * then allocatable space for all packages in your shared UID is tracked * together as a single unit. * </p> * - * @param path the path where you're considering allocating disk space, - * since allocatable space can vary widely depending on the - * underlying storage device. + * @param storageUuid the UUID of the storage volume where you're + * considering allocating disk space, since allocatable space can + * vary widely depending on the underlying storage device. The + * UUID for a specific path can be obtained using + * {@link #getUuidForPath(File)}. * @param flags to apply to the request. * @return the maximum number of new bytes that the calling app can allocate - * using {@link #allocateBytes(File, long, int)}. + * using {@link #allocateBytes(UUID, long, int)} or + * {@link #allocateBytes(FileDescriptor, long, int)}. + * @throws IOException when the storage device isn't present, or when it + * doesn't support allocating space. */ - public long getAllocatableBytes(File path, @AllocateFlags int flags) throws IOException { + public long getAllocatableBytes(@NonNull UUID storageUuid, @AllocateFlags int flags) + throws IOException { try { - final String volumeUuid = findUuidForPath(path); - return mStorageManager.getAllocatableBytes(volumeUuid, flags); + return mStorageManager.getAllocatableBytes(convert(storageUuid), flags); } catch (ParcelableException e) { e.maybeRethrow(IOException.class); throw new RuntimeException(e); @@ -1592,28 +1688,40 @@ public class StorageManager { } } + /** @removed */ + @Deprecated + public long getAllocatableBytes(@NonNull File path, @AllocateFlags int flags) + throws IOException { + return getAllocatableBytes(getUuidForPath(path), flags); + } + /** - * Allocate the requested number of bytes for your application to use at the - * given path. This will cause the system to delete any cached files - * necessary to satisfy your request. + * Allocate the requested number of bytes for your application to use on the + * given storage volume. This will cause the system to delete any cached + * files necessary to satisfy your request. * <p> * Attempts to allocate disk space beyond the value returned by - * {@link #getAllocatableBytes(File, int)} will fail. + * {@link #getAllocatableBytes(UUID, int)} will fail. * <p> * Since multiple apps can be running simultaneously, this method may be * subject to race conditions. If possible, consider using * {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee * that bytes are allocated to an opened file. * - * @param path the path where you'd like to allocate disk space. + * @param storageUuid the UUID of the storage volume where you'd like to + * allocate disk space. The UUID for a specific path can be + * obtained using {@link #getUuidForPath(File)}. * @param bytes the number of bytes to allocate. * @param flags to apply to the request. - * @see #getAllocatableBytes(File, int) + * @throws IOException when the storage device isn't present, or when it + * doesn't support allocating space, or if the device had + * trouble allocating the requested space. + * @see #getAllocatableBytes(UUID, int) */ - public void allocateBytes(File path, long bytes, @AllocateFlags int flags) throws IOException { + public void allocateBytes(@NonNull UUID storageUuid, long bytes, @AllocateFlags int flags) + throws IOException { try { - final String volumeUuid = findUuidForPath(path); - mStorageManager.allocateBytes(volumeUuid, bytes, flags); + mStorageManager.allocateBytes(convert(storageUuid), bytes, flags); } catch (ParcelableException e) { e.maybeRethrow(IOException.class); } catch (RemoteException e) { @@ -1621,13 +1729,20 @@ public class StorageManager { } } + /** @removed */ + @Deprecated + public void allocateBytes(@NonNull File path, long bytes, @AllocateFlags int flags) + throws IOException { + allocateBytes(getUuidForPath(path), bytes, flags); + } + /** * Allocate the requested number of bytes for your application to use in the * given open file. This will cause the system to delete any cached files * necessary to satisfy your request. * <p> * Attempts to allocate disk space beyond the value returned by - * {@link #getAllocatableBytes(File, int)} will fail. + * {@link #getAllocatableBytes(UUID, int)} will fail. * <p> * This method guarantees that bytes have been allocated to the opened file, * otherwise it will throw if fast allocation is not possible. Fast @@ -1636,9 +1751,15 @@ public class StorageManager { * * @param fd the open file that you'd like to allocate disk space for. * @param bytes the number of bytes to allocate. This is the desired final - * size of the open file. + * size of the open file. If the open file is smaller than this + * requested size, it will be extended without modifying any + * existing contents. If the open file is larger than this + * requested size, it will be truncated. * @param flags to apply to the request. - * @see #getAllocatableBytes(File, int) + * @throws IOException when the storage device isn't present, or when it + * doesn't support allocating space, or if the device had + * trouble allocating the requested space. + * @see #getAllocatableBytes(UUID, int) * @see Environment#isExternalStorageEmulated(File) */ public void allocateBytes(FileDescriptor fd, long bytes, @AllocateFlags int flags) @@ -1777,6 +1898,32 @@ public class StorageManager { return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE); } + /** {@hide} */ + public static UUID convert(String uuid) { + if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) { + return UUID_DEFAULT; + } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) { + return UUID_PRIMARY_PHYSICAL_; + } else if (Objects.equals(uuid, UUID_SYSTEM)) { + return UUID_SYSTEM_; + } else { + return UUID.fromString(uuid); + } + } + + /** {@hide} */ + public static String convert(UUID storageUuid) { + if (UUID_DEFAULT.equals(storageUuid)) { + return UUID_PRIVATE_INTERNAL; + } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) { + return UUID_PRIMARY_PHYSICAL; + } else if (UUID_SYSTEM_.equals(storageUuid)) { + return UUID_SYSTEM; + } else { + return storageUuid.toString(); + } + } + private final Object mFuseAppLoopLock = new Object(); @GuardedBy("mFuseAppLoopLock") diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 539559d19c82..c6ea9586374d 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8330,7 +8330,6 @@ public final class Settings { * enabled state. * @hide */ - @SystemApi public static final String NETWORK_RECOMMENDATIONS_ENABLED = "network_recommendations_enabled"; 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/packages/SystemUI/res/values/dimens_tv.xml b/core/java/android/service/autofill/FillRequest.aidl index 30355d47e957..2b1a8fea8a5e 100644 --- a/packages/SystemUI/res/values/dimens_tv.xml +++ b/core/java/android/service/autofill/FillRequest.aidl @@ -1,7 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* - * Copyright 2016, The Android Open Source Project +/** + * 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. @@ -15,8 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ ---> -<resources> - <!-- Extra space around the PIP and its outline in PIP onboarding activity --> - <dimen name="tv_pip_bounds_space">3dp</dimen> -</resources> + +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..7f960dff0bdf 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -21,6 +21,7 @@ import static android.view.autofill.Helper.DEBUG; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.assist.AssistStructure; import android.content.IntentSender; import android.os.Bundle; import android.os.Parcel; @@ -140,12 +141,25 @@ 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; private final AutofillId[] mOptionalIds; private final CharSequence mDescription; + private final boolean mSaveOnAllViewsInvisible; private SaveInfo(Builder builder) { mType = builder.mType; @@ -154,6 +168,7 @@ public final class SaveInfo implements Parcelable { mRequiredIds = builder.mRequiredIds; mOptionalIds = builder.mOptionalIds; mDescription = builder.mDescription; + mSaveOnAllViewsInvisible = builder.mSaveOnAllViewsInvisible; } /** @hide */ @@ -177,11 +192,16 @@ public final class SaveInfo implements Parcelable { } /** @hide */ - public int getType() { + public @SaveDataType int getType() { return mType; } /** @hide */ + public boolean saveOnAllViewsInvisible() { + return mSaveOnAllViewsInvisible; + } + + /** @hide */ public CharSequence getDescription() { return mDescription; } @@ -191,7 +211,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 @@ -199,6 +219,7 @@ public final class SaveInfo implements Parcelable { private AutofillId[] mOptionalIds; private CharSequence mDescription; private boolean mDestroyed; + private boolean mSaveOnAllViewsInvisible; /** * Creates a new builder. @@ -215,7 +236,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 +251,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); } @@ -247,6 +268,21 @@ public final class SaveInfo implements Parcelable { } /** + * Usually {@link AutofillService#onSaveRequest(AssistStructure, Bundle, SaveCallback)} + * is called once the activity finishes. If this property is set it is called once all + * autofillable or saved views become invisible. + * + * @param saveOnAllViewsInvisible Set to {@code true} if the data should be saved once + * all the views become invisible. + * @return This builder. + */ + public @NonNull Builder setSaveOnAllViewsInvisible(boolean saveOnAllViewsInvisible) { + throwIfDestroyed(); + mSaveOnAllViewsInvisible = saveOnAllViewsInvisible; + return this; + } + + /** * Sets the ids of additional, optional views the service would be interested to save. * * <p>See {@link SaveInfo} for more info. @@ -342,6 +378,7 @@ public final class SaveInfo implements Parcelable { .append(", requiredIds=").append(Arrays.toString(mRequiredIds)) .append(", optionalIds=").append(Arrays.toString(mOptionalIds)) .append(", description=").append(mDescription) + .append(", saveOnNoVisibleTrackedViews=").append(mSaveOnAllViewsInvisible) .append("]").toString(); } @@ -362,6 +399,7 @@ public final class SaveInfo implements Parcelable { parcel.writeParcelable(mNegativeActionListener, flags); parcel.writeParcelableArray(mOptionalIds, flags); parcel.writeCharSequence(mDescription); + parcel.writeBoolean(mSaveOnAllViewsInvisible); } public static final Parcelable.Creator<SaveInfo> CREATOR = new Parcelable.Creator<SaveInfo>() { @@ -375,6 +413,7 @@ public final class SaveInfo implements Parcelable { builder.setNegativeAction(parcel.readCharSequence(), parcel.readParcelable(null)); builder.setOptionalIds(parcel.readParcelableArray(null, AutofillId.class)); builder.setDescription(parcel.readCharSequence()); + builder.setSaveOnAllViewsInvisible(parcel.readBoolean()); return builder.build(); } 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/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index dc1a70d74d7f..ed44f2599695 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -18,6 +18,7 @@ package android.service.notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; +import android.os.UserHandle; import android.service.notification.IStatusBarNotificationHolder; import android.service.notification.StatusBarNotification; import android.service.notification.NotificationRankingUpdate; @@ -36,8 +37,8 @@ oneway interface INotificationListener void onInterruptionFilterChanged(int interruptionFilter); // companion device managers only - void onNotificationChannelModification(String pkgName, in NotificationChannel channel, int modificationType); - void onNotificationChannelGroupModification(String pkgName, in NotificationChannelGroup group, int modificationType); + void onNotificationChannelModification(String pkgName, in UserHandle user, in NotificationChannel channel, int modificationType); + void onNotificationChannelGroupModification(String pkgName, in UserHandle user, in NotificationChannelGroup group, int modificationType); // rankers only void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 4833be335c88..00bd30456c9e 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -49,6 +49,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -231,25 +232,25 @@ public abstract class NotificationListenerService extends Service { /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was created. + * {@link #onNotificationChannelModified(String, UserHandle,NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, + * int)}- the provided object was created. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was updated. + * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle,NotificationChannelGroup, int)} + * - the provided object was updated. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; /** * Channel or group modification reason provided to - * {@link #onNotificationChannelModified(String, NotificationChannel, int)} or - * {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the - * provided object was deleted. + * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or + * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, + * int)}- the provided object was deleted. */ public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; @@ -432,13 +433,14 @@ public abstract class NotificationListenerService extends Service { * device} in order to receive this callback. * * @param pkg The package the channel belongs to. + * @param user The user on which the change was made. * @param channel The channel that has changed. * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. */ - public void onNotificationChannelModified(String pkg, NotificationChannel channel, - @ChannelOrGroupModificationTypes int modificationType) { + public void onNotificationChannelModified(String pkg, UserHandle user, + NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { // optional } @@ -449,13 +451,14 @@ public abstract class NotificationListenerService extends Service { * device} in order to receive this callback. * * @param pkg The package the group belongs to. + * @param user The user on which the change was made. * @param group The group that has changed. * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. */ - public void onNotificationChannelGroupModified(String pkg, NotificationChannelGroup group, - @ChannelOrGroupModificationTypes int modificationType) { + public void onNotificationChannelGroupModified(String pkg, UserHandle user, + NotificationChannelGroup group, @ChannelOrGroupModificationTypes int modificationType) { // optional } @@ -661,21 +664,24 @@ public abstract class NotificationListenerService extends Service { /** - * Updates a notification channel for a given package. This should only be used to reflect - * changes a user has made to the channel via the listener's user interface. + * Updates a notification channel for a given package for a given user. This should only be used + * to reflect changes a user has made to the channel via the listener's user interface. * + * <p>This method will throw a security exception if you don't have access to notifications + * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package the channel belongs to. + * @param user The user the channel belongs to. * @param channel the channel to update. */ - public final void updateNotificationChannel(@NonNull String pkg, + public final void updateNotificationChannel(@NonNull String pkg, @NonNull UserHandle user, @NonNull NotificationChannel channel) { if (!isBound()) return; try { getNotificationInterface().updateNotificationChannelFromPrivilegedListener( - mWrapper, pkg, channel); + mWrapper, pkg, user, channel); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -683,19 +689,22 @@ public abstract class NotificationListenerService extends Service { } /** - * Returns all notification channels belonging to the given package. + * Returns all notification channels belonging to the given package for a given user. * + * <p>This method will throw a security exception if you don't have access to notifications + * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package to retrieve channels for. */ - public final List<NotificationChannel> getNotificationChannels(@NonNull String pkg) { + public final List<NotificationChannel> getNotificationChannels(@NonNull String pkg, + @NonNull UserHandle user) { if (!isBound()) return null; try { return getNotificationInterface().getNotificationChannelsFromPrivilegedListener( - mWrapper, pkg).getList(); + mWrapper, pkg, user).getList(); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -703,19 +712,22 @@ public abstract class NotificationListenerService extends Service { } /** - * Returns all notification channel groups belonging to the given package. + * Returns all notification channel groups belonging to the given package for a given user. * + * <p>This method will throw a security exception if you don't have access to notifications + * for the given user.</p> * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated * device} in order to use this method. * * @param pkg The package to retrieve channel groups for. */ - public final List<NotificationChannelGroup> getNotificationChannelGroups(@NonNull String pkg) { + public final List<NotificationChannelGroup> getNotificationChannelGroups(@NonNull String pkg, + @NonNull UserHandle user) { if (!isBound()) return null; try { return getNotificationInterface().getNotificationChannelGroupsFromPrivilegedListener( - mWrapper, pkg).getList(); + mWrapper, pkg, user).getList(); } catch (RemoteException e) { Log.v(TAG, "Unable to contact notification manager", e); throw e.rethrowFromSystemServer(); @@ -1252,24 +1264,27 @@ public abstract class NotificationListenerService extends Service { } @Override - public void onNotificationChannelModification(String pkgName, NotificationChannel channel, + public void onNotificationChannelModification(String pkgName, UserHandle user, + NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { SomeArgs args = SomeArgs.obtain(); args.arg1 = pkgName; - args.arg2 = channel; - args.arg3 = modificationType; + args.arg2 = user; + args.arg3 = channel; + args.arg4 = modificationType; mHandler.obtainMessage( MyHandler.MSG_ON_NOTIFICATION_CHANNEL_MODIFIED, args).sendToTarget(); } @Override - public void onNotificationChannelGroupModification(String pkgName, + public void onNotificationChannelGroupModification(String pkgName, UserHandle user, NotificationChannelGroup group, @ChannelOrGroupModificationTypes int modificationType) { SomeArgs args = SomeArgs.obtain(); args.arg1 = pkgName; - args.arg2 = group; - args.arg3 = modificationType; + args.arg2 = user; + args.arg3 = group; + args.arg4 = modificationType; mHandler.obtainMessage( MyHandler.MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED, args).sendToTarget(); } @@ -1841,17 +1856,19 @@ public abstract class NotificationListenerService extends Service { case MSG_ON_NOTIFICATION_CHANNEL_MODIFIED: { SomeArgs args = (SomeArgs) msg.obj; String pkgName = (String) args.arg1; - NotificationChannel channel = (NotificationChannel) args.arg2; - int modificationType = (int) args.arg3; - onNotificationChannelModified(pkgName, channel, modificationType); + UserHandle user= (UserHandle) args.arg2; + NotificationChannel channel = (NotificationChannel) args.arg3; + int modificationType = (int) args.arg4; + onNotificationChannelModified(pkgName, user, channel, modificationType); } break; case MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED: { SomeArgs args = (SomeArgs) msg.obj; String pkgName = (String) args.arg1; - NotificationChannelGroup group = (NotificationChannelGroup) args.arg2; - int modificationType = (int) args.arg3; - onNotificationChannelGroupModified(pkgName, group, modificationType); + UserHandle user = (UserHandle) args.arg2; + NotificationChannelGroup group = (NotificationChannelGroup) args.arg3; + int modificationType = (int) args.arg4; + onNotificationChannelGroupModified(pkgName, user, group, modificationType); } break; } } 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/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl index 2fe98c0b6f05..dbeb747adfba 100644 --- a/core/java/android/view/IPinnedStackController.aidl +++ b/core/java/android/view/IPinnedStackController.aidl @@ -28,4 +28,9 @@ interface IPinnedStackController { * Notifies the controller that the PiP is currently minimized. */ oneway void setIsMinimized(boolean isMinimized); + + /** + * @return what WM considers to be the current device rotation. + */ + int getDisplayRotation(); } diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl index 782f3499fb79..9382741a81ec 100644 --- a/core/java/android/view/IPinnedStackListener.aidl +++ b/core/java/android/view/IPinnedStackListener.aidl @@ -41,9 +41,13 @@ oneway interface IPinnedStackListener { * current state with the aspect ratio applied. The {@param animatingBounds} are provided * to indicate the current target bounds of the pinned stack (the final bounds if animating, * the current bounds if not), which may be helpful in calculating dependent animation bounds. + * + * The {@param displayRotation} is provided so that the client can verify when making certain + * calls that it will not provide stale information based on an old display rotation (ie. if + * the WM has changed in the mean time but the client has not received onMovementBoundsChanged). */ void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds, - boolean fromImeAdjustement); + boolean fromImeAdjustement, int displayRotation); /** * Called when window manager decides to adjust the pinned stack bounds because of the IME, or diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index a522652437ba..7d2d77e251a9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -66,6 +66,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -109,7 +110,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 +954,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 +2727,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 +2957,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. */ @@ -4433,6 +4381,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Nullable private RoundScrollbarRenderer mRoundScrollbarRenderer; + /** Used to delay visibility updates sent to the autofill manager */ + private Handler mVisibilityChangeForAutofillHandler; + /** * Simple constructor to use when creating a view from code. * @@ -5055,11 +5006,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 +6795,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 +9104,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 +9740,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. * @@ -11812,6 +11700,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (fg != null && isVisible != fg.isVisible()) { fg.setVisible(isVisible, false); } + + if (isAutofillable()) { + AutofillManager afm = getAutofillManager(); + + if (afm != null && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID) { + if (mVisibilityChangeForAutofillHandler != null) { + mVisibilityChangeForAutofillHandler.removeMessages(0); + } + + // If the view is in the background but still part of the hierarchy this is called + // with isVisible=false. Hence visibility==false requires further checks + if (isVisible) { + afm.notifyViewVisibilityChange(this, true); + } else { + if (mVisibilityChangeForAutofillHandler == null) { + mVisibilityChangeForAutofillHandler = + new VisibilityChangeForAutofillHandler(afm, this); + } + // Let current operation (e.g. removal of the view from the hierarchy) + // finish before checking state + mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); + } + } + } } /** @@ -24608,6 +24520,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * When a view becomes invisible checks if autofill considers the view invisible too. This + * happens after the regular removal operation to make sure the operation is finished by the + * time this is called. + */ + private static class VisibilityChangeForAutofillHandler extends Handler { + private final AutofillManager mAfm; + private final View mView; + + private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, + @NonNull View view) { + mAfm = afm; + mView = view; + } + + @Override + public void handleMessage(Message msg) { + mAfm.notifyViewVisibilityChange(mView, mView.isShown()); + } + } + + /** * Base class for derived classes that want to save and restore their own * state in {@link android.view.View#onSaveInstanceState()}. */ 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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index a7ececf6c782..080ffeb011f8 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1561,6 +1561,16 @@ public final class ViewRootImpl implements ViewParent, host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */)); } + /** + * @return the last content insets for use in adjusting the source hint rect for the + * picture-in-picture transition. + * + * @hide + */ + public Rect getLastContentInsets() { + return mAttachInfo.mContentInsets; + } + private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) { return lp.type == TYPE_STATUS_BAR_PANEL || lp.type == TYPE_INPUT_METHOD diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 6dbc09ceef97..bf0e10f993ad 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -303,13 +303,16 @@ public abstract class WindowManagerInternal { * hidden, no matter how WindowManagerService will react / has reacted * to corresponding API calls. Note that this state is not guaranteed * to be synchronized with state in WindowManagerService. + * @param dismissImeOnBackKeyPressed {@code true} if the software keyboard is shown and the back + * key is expected to dismiss the software keyboard. * @param targetWindowToken token to identify the target window that the IME is associated with. * {@code null} when application, system, or the IME itself decided to * change its window visibility before being associated with any target * window. */ public abstract void updateInputMethodWindowStatus(@NonNull IBinder imeToken, - boolean imeWindowVisible, @Nullable IBinder targetWindowToken); + boolean imeWindowVisible, boolean dismissImeOnBackKeyPressed, + @Nullable IBinder targetWindowToken); /** * Returns true when the hardware keyboard is available. diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index bb6e0eed57cc..030c78b7f4b6 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1537,6 +1537,18 @@ public interface WindowManagerPolicy { public void setLastInputMethodWindowLw(WindowState ime, WindowState target); /** + * An internal callback (from InputMethodManagerService) to notify a state change regarding + * whether the back key should dismiss the software keyboard (IME) or not. + * + * @param newValue {@code true} if the software keyboard is shown and the back key is expected + * to dismiss the software keyboard. + * @hide + */ + default void setDismissImeOnBackKeyPressed(boolean newValue) { + // Default implementation does nothing. + } + + /** * Show the recents task list app. * @hide */ diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 41c209cc016a..f9f400d83b09 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -32,6 +32,7 @@ import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.view.View; @@ -101,7 +102,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 @@ -140,6 +144,10 @@ public final class AutofillManager { @GuardedBy("mLock") @Nullable private ParcelableMap mLastAutofilledData; + /** If view tracking is enabled, contains the tracking state */ + @GuardedBy("mLock") + @Nullable private TrackedViews mTrackedViews; + /** @hide */ public interface AutofillClient { /** @@ -174,6 +182,20 @@ public final class AutofillManager { * @return Whether the UI was hidden. */ boolean autofillCallbackRequestHideFillUi(); + + /** + * Checks if the view is currently attached and visible. + * + * @return {@code true} iff the view is attached or visible + */ + boolean getViewVisibility(int viewId); + + /** + * Checks is the client is currently visible as understood by autofill. + * + * @return {@code true} if the client is currently visible + */ + boolean isVisibleForAutofill(); } /** @@ -257,6 +279,21 @@ public final class AutofillManager { } /** + * Called once the client becomes visible. + * + * @see AutofillClient#isVisibleForAutofill() + * + * {@hide} + */ + public void onVisibleForAutofill() { + synchronized (mLock) { + if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) { + mTrackedViews.onVisibleForAutofill(); + } + } + } + + /** * Save state before activity lifecycle * * @param outState Place to store the state @@ -409,6 +446,22 @@ public final class AutofillManager { } /** + * Called when a {@link View view's} visibility changes. + * + * @param view {@link View} that was exited. + * @param isVisible visible if the view is visible in the view hierarchy. + * + * @hide + */ + public void notifyViewVisibilityChange(@NonNull View view, boolean isVisible) { + synchronized (mLock) { + if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) { + mTrackedViews.notifyViewVisibilityChange(view, isVisible); + } + } + } + + /** * Called when a virtual view that supports autofill is entered. * * @param view the {@link View} whose descendant is the virtual view. @@ -666,6 +719,7 @@ public final class AutofillManager { throw e.rethrowFromSystemServer(); } + mTrackedViews = null; mSessionId = NO_SESSION; } @@ -680,6 +734,7 @@ public final class AutofillManager { throw e.rethrowFromSystemServer(); } + mTrackedViews = null; mSessionId = NO_SESSION; } @@ -760,8 +815,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 +824,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 +846,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 +882,111 @@ 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); + /** + * Set the tracked views. + * + * @param trackedIds The views to be tracked + * @param saveOnAllViewsInvisible Finish the session once all tracked views are invisible. + */ + private void setTrackedViews(int sessionId, List<AutofillId> trackedIds, + boolean saveOnAllViewsInvisible) { + synchronized (mLock) { + if (mEnabled && mSessionId == sessionId) { + if (saveOnAllViewsInvisible) { + mTrackedViews = new TrackedViews(trackedIds); + } else { + mTrackedViews = null; + } + } + } } - 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 +1000,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) { @@ -929,6 +1040,195 @@ public final class AutofillManager { } /** + * View tracking information. Once all tracked views become invisible the session is finished. + */ + private class TrackedViews { + /** Visible tracked views */ + @Nullable private ArraySet<AutofillId> mVisibleTrackedIds; + + /** Invisible tracked views */ + @Nullable private ArraySet<AutofillId> mInvisibleTrackedIds; + + /** + * Check if set is null or value is in set. + * + * @param set The set or null (== empty set) + * @param value The value that might be in the set + * + * @return {@code true} iff set is not empty and value is in set + */ + private <T> boolean isInSet(@Nullable ArraySet<T> set, T value) { + return set != null && set.contains(value); + } + + /** + * Add a value to a set. If set is null, create a new set. + * + * @param set The set or null (== empty set) + * @param valueToAdd The value to add + * + * @return The set including the new value. If set was {@code null}, a set containing only + * the new value. + */ + @NonNull + private <T> ArraySet<T> addToSet(@Nullable ArraySet<T> set, T valueToAdd) { + if (set == null) { + set = new ArraySet<>(1); + } + + set.add(valueToAdd); + + return set; + } + + /** + * Remove a value from a set. + * + * @param set The set or null (== empty set) + * @param valueToRemove The value to remove + * + * @return The set without the removed value. {@code null} if set was null, or is empty + * after removal. + */ + @Nullable + private <T> ArraySet<T> removeFromSet(@Nullable ArraySet<T> set, T valueToRemove) { + if (set == null) { + return null; + } + + set.remove(valueToRemove); + + if (set.isEmpty()) { + return null; + } + + return set; + } + + /** + * Set the tracked views. + * + * @param trackedIds The views to be tracked + */ + TrackedViews(@NonNull List<AutofillId> trackedIds) { + mVisibleTrackedIds = null; + mInvisibleTrackedIds = null; + + AutofillClient client = getClientLocked(); + if (trackedIds != null) { + int numIds = trackedIds.size(); + for (int i = 0; i < numIds; i++) { + AutofillId id = trackedIds.get(i); + + boolean isVisible = true; + if (client != null && client.isVisibleForAutofill()) { + isVisible = client.getViewVisibility(id.getViewId()); + } + + if (isVisible) { + mVisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); + } else { + mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); + } + } + } + + if (DEBUG) { + Log.d(TAG, "TrackedViews(trackedIds=" + trackedIds + "): " + + " mVisibleTrackedIds=" + mVisibleTrackedIds + + " mInvisibleTrackedIds=" + mInvisibleTrackedIds); + } + + if (mVisibleTrackedIds == null) { + finishSessionLocked(); + } + } + + /** + * Called when a {@link View view's} visibility changes. + * + * @param view {@link View} that was exited. + * @param isVisible visible if the view is visible in the view hierarchy. + */ + void notifyViewVisibilityChange(@NonNull View view, boolean isVisible) { + AutofillId id = getAutofillId(view); + AutofillClient client = getClientLocked(); + + if (DEBUG) { + Log.d(TAG, "notifyViewVisibilityChange(): id=" + id + " isVisible=" + + isVisible); + } + + if (client != null && client.isVisibleForAutofill()) { + if (isVisible) { + if (isInSet(mInvisibleTrackedIds, id)) { + mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id); + mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id); + } + } else { + if (isInSet(mVisibleTrackedIds, id)) { + mVisibleTrackedIds = removeFromSet(mVisibleTrackedIds, id); + mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); + } + } + } + + if (mVisibleTrackedIds == null) { + finishSessionLocked(); + } + } + + /** + * Called once the client becomes visible. + * + * @see AutofillClient#isVisibleForAutofill() + */ + void onVisibleForAutofill() { + // The visibility of the views might have changed while the client was not started, + // hence update the visibility state for all views. + AutofillClient client = getClientLocked(); + ArraySet<AutofillId> updatedVisibleTrackedIds = null; + ArraySet<AutofillId> updatedInvisibleTrackedIds = null; + if (client != null) { + if (mInvisibleTrackedIds != null) { + for (AutofillId id : mInvisibleTrackedIds) { + if (client.getViewVisibility(id.getViewId())) { + updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id); + + if (DEBUG) { + Log.i(TAG, "onVisibleForAutofill() " + id + " became visible"); + } + } else { + updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id); + } + } + } + + if (mVisibleTrackedIds != null) { + for (AutofillId id : mVisibleTrackedIds) { + if (client.getViewVisibility(id.getViewId())) { + updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id); + } else { + updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id); + + if (DEBUG) { + Log.i(TAG, "onVisibleForAutofill() " + id + " became invisible"); + } + } + } + } + + mInvisibleTrackedIds = updatedInvisibleTrackedIds; + mVisibleTrackedIds = updatedVisibleTrackedIds; + } + + if (mVisibleTrackedIds == null) { + finishSessionLocked(); + } + } + } + + /** * Callback for auto-fill related events. * * <p>Typically used for applications that display their own "auto-complete" views, so they can @@ -999,73 +1299,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)); } } @@ -1082,5 +1366,16 @@ public final class AutofillManager { }); } } + + @Override + public void setTrackedViews(int sessionId, List<AutofillId> ids, + boolean saveOnAllViewsInvisible) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + afm.mContext.getMainThreadHandler().post( + () -> afm.setTrackedViews(sessionId, ids, saveOnAllViewsInvisible) + ); + } + } } } diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index 176eaacb57ae..1a6bad2d1cd6 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -40,28 +40,36 @@ 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); + + /** + * Sets the views to track. If saveOnAllViewsInvisible is set and all these view are invisible + * the session is finished automatically. + */ + void setTrackedViews(int sessionId, in List<AutofillId> ids, + boolean saveOnAllViewsInvisible); /** * 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/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java index 6c6079f202fd..d11c03ad6878 100644 --- a/core/java/android/widget/Chronometer.java +++ b/core/java/android/widget/Chronometer.java @@ -17,11 +17,13 @@ package android.widget; import android.content.Context; +import android.content.Intent; import android.content.res.TypedArray; import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; import android.icu.util.MeasureUnit; +import android.net.Uri; import android.os.SystemClock; import android.text.format.DateUtils; import android.util.AttributeSet; @@ -148,6 +150,22 @@ public class Chronometer extends TextView { } /** + * @return whether this is the final countdown + */ + public boolean isTheFinalCountDown() { + try { + getContext().startActivity( + new Intent(Intent.ACTION_VIEW, Uri.parse("https://youtu.be/9jK-NcRmVcw")) + .addCategory(Intent.CATEGORY_BROWSABLE) + .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT + | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)); + return true; + } catch (Exception e) { + return false; + } + } + + /** * Set the time that the count-up timer is in reference to. * * @param base Use the {@link SystemClock#elapsedRealtime} time base. diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 4fb7b19f7bf7..0d3baa8361ba 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -146,7 +146,7 @@ public class Editor { private static final String UNDO_OWNER_TAG = "Editor"; // Ordering constants used to place the Action Mode or context menu items in their menu. - private static final int MENU_ITEM_ORDER_ASSIST = 1; + private static final int MENU_ITEM_ORDER_ASSIST = 0; private static final int MENU_ITEM_ORDER_UNDO = 2; private static final int MENU_ITEM_ORDER_REDO = 3; private static final int MENU_ITEM_ORDER_CUT = 4; @@ -156,8 +156,8 @@ public class Editor { private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 8; private static final int MENU_ITEM_ORDER_SELECT_ALL = 9; private static final int MENU_ITEM_ORDER_REPLACE = 10; - private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 11; - private static final int MENU_ITEM_ORDER_AUTOFILL = 12; + private static final int MENU_ITEM_ORDER_AUTOFILL = 11; + private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100; // Each Editor manages its own undo stack. private final UndoManager mUndoManager = new UndoManager(); @@ -6322,9 +6322,10 @@ public class Editor { * Adds "PROCESS_TEXT" menu items to the specified menu. */ public void onInitializeMenu(Menu menu) { - int i = 0; + final int size = mSupportedActivities.size(); loadSupportedActivities(); - for (ResolveInfo resolveInfo : mSupportedActivities) { + for (int i = 0; i < size; i++) { + final ResolveInfo resolveInfo = mSupportedActivities.get(i); menu.add(Menu.NONE, Menu.NONE, Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i++, getLabel(resolveInfo)) diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index f9f10af85b69..f1a3ff54ed80 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8196,9 +8196,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mTempTextPaint.set(getPaint()); mTempTextPaint.setTextSize(suggestedSizeInPx); + final int availableWidth = mHorizontallyScrolling + ? VERY_WIDE + : getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight(); final StaticLayout.Builder layoutBuilder = StaticLayout.Builder.obtain( - text, 0, text.length(), mTempTextPaint, - getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight()); + text, 0, text.length(), mTempTextPaint, availableWidth); layoutBuilder.setAlignment(getLayoutAlignment()) .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier()) diff --git a/core/java/com/android/internal/app/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/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index baf6db93daaf..80b6b0848a0b 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -82,6 +82,7 @@ import android.widget.PopupWindow; import static android.app.ActivityManager.StackId; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; @@ -2182,19 +2183,22 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind final boolean wasAdjustedForStack = mElevationAdjustedForStack; // Do not use a shadow when we are in resizing mode (mBackdropFrameRenderer not null) // since the shadow is bound to the content size and not the target size. - if (StackId.hasWindowShadow(mStackId) && !isResizing()) { + if ((mStackId == FREEFORM_WORKSPACE_STACK_ID) && !isResizing()) { elevation = hasWindowFocus() ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; // Add a maximum shadow height value to the top level view. // Note that pinned stack doesn't have focus // so maximum shadow height adjustment isn't needed. // TODO(skuhne): Remove this if clause once b/22668382 got fixed. - if (!mAllowUpdateElevation && mStackId != PINNED_STACK_ID) { + if (!mAllowUpdateElevation) { elevation = DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; } // Convert the DP elevation into physical pixels. elevation = dipToPx(elevation); mElevationAdjustedForStack = true; + } else if (mStackId == PINNED_STACK_ID) { + elevation = dipToPx(DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP); + mElevationAdjustedForStack = true; } else { mElevationAdjustedForStack = false; } 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/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 818cc2c2421d..8c71cf7006ff 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -233,6 +233,7 @@ public final class FloatingToolbar { private void doShow() { List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); + tidy(menuItems); if (!isCurrentlyShowing(menuItems) || mWidthChanged) { mPopup.dismiss(); mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); @@ -274,6 +275,36 @@ public final class FloatingToolbar { return menuItems; } + /** + * Update the list of menu items to conform to certain requirements. + */ + private void tidy(List<MenuItem> menuItems) { + int assistItemIndex = -1; + Drawable assistItemDrawable = null; + + final int size = menuItems.size(); + for (int i = 0; i < size; i++) { + final MenuItem menuItem = menuItems.get(i); + + if (menuItem.getItemId() == android.R.id.textAssist) { + assistItemIndex = i; + assistItemDrawable = menuItem.getIcon(); + } + + // Remove icons for all menu items with text. + if (!TextUtils.isEmpty(menuItem.getTitle())) { + menuItem.setIcon(null); + } + } + if (assistItemIndex > -1) { + final MenuItem assistMenuItem = menuItems.remove(assistItemIndex); + // Ensure the assist menu item preserves its icon. + assistMenuItem.setIcon(assistItemDrawable); + // Ensure the assist menu item is always the first item. + menuItems.add(0, assistMenuItem); + } + } + private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) { List<Object> references = new ArrayList<Object>(); for (MenuItem menuItem : menuItems) { diff --git a/core/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..9355cfcdb0d3 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,16 +196,29 @@ 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. if (javaBitmap) { recycleAlloc.copyIfNecessary(); + bitmap::reinitBitmap(env, javaBitmap, recycledBitmap->info(), !requireUnpremul); return javaBitmap; } diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index e66587a9d8fe..b11fd4fce714 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); @@ -510,7 +658,11 @@ bool RecyclingClippingPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTab // mRecycledBitmap->info() for the SkImageInfo. According to the // specification for BitmapRegionDecoder, we are not allowed to change // the SkImageInfo. - mRecycledBitmap->reconfigure(mRecycledBitmap->info(), rowBytes, ctable); + // We can (must) preserve the color space since it doesn't affect the + // storage needs + mRecycledBitmap->reconfigure( + mRecycledBitmap->info().makeColorSpace(bitmap->refColorSpace()), + rowBytes, ctable); // Give the bitmap the same pixelRef as mRecycledBitmap. // skbug.com/4538: We also need to make sure that the rowBytes on the pixel ref @@ -577,74 +729,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_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index 520302ee02b9..2c7174d71c6b 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -24,6 +24,7 @@ #include <ScopedLocalRef.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_hardware_HardwareBuffer.h> +#include <vndk/hardware_buffer.h> #include <sensor/Sensor.h> #include <sensor/SensorEventQueue.h> #include <sensor/SensorManager.h> 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/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 569646820402..95ba94209343 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2439,6 +2439,14 @@ <!-- Whether the given RRO is static or not. --> <attr name="isStatic" format="boolean" /> + <!-- Required property name/value pair used to enable this overlay. + e.g. name=ro.oem.sku value=MKT210. + Overlay will be ignored unless system property exists and is + set to specified value --> + <!-- @hide @SystemApi This shouldn't be public. --> + <attr name="requiredSystemPropertyName" format="string" /> + <!-- @hide @SystemApi This shouldn't be public. --> + <attr name="requiredSystemPropertyValue" format="string" /> </declare-styleable> <!-- Declaration of an {@link android.content.Intent} object in XML. May diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 45dccb6bfe33..6a31e161842b 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -852,6 +852,8 @@ 1 - Go to sleep (doze) 2 - Really go to sleep (don't doze) 3 - Really go to sleep and go home (don't doze) + 4 - Go to home + 5 - Dismiss IME if shown. Otherwise go to home --> <integer name="config_shortPressOnPowerBehavior">1</integer> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d6ed1786e760..9e98efde2c73 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" /> @@ -2817,6 +2817,10 @@ <public name="defaultFocusHighlightEnabled" /> <public name="persistentFeature"/> <public name="windowSplashscreenContent" /> + <!-- @hide @SystemApi --> + <public name="requiredSystemPropertyName" /> + <!-- @hide @SystemApi --> + <public name="requiredSystemPropertyValue" /> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 08216742add5..bd350730a8e2 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3000,6 +3000,8 @@ <!-- Do not translate. Default access point SSID used for tethering --> <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string> + <!-- Do not translate. Default access point SSID used for local only hotspot --> + <string name="wifi_localhotspot_configure_ssid_default" translatable="false">AndroidShare</string> <!-- A notification is shown the first time a connection is attempted on an app owned AP --> <!-- title for this message --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 603e3769e75c..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" /> @@ -1003,6 +1006,7 @@ <java-symbol type="string" name="wifi_p2p_turnon_message" /> <java-symbol type="string" name="wifi_p2p_frequency_conflict_message" /> <java-symbol type="string" name="wifi_tether_configure_ssid_default" /> + <java-symbol type="string" name="wifi_localhotspot_configure_ssid_default" /> <java-symbol type="string" name="wifi_watchdog_network_disabled" /> <java-symbol type="string" name="wifi_watchdog_network_disabled_detailed" /> <java-symbol type="string" name="imei" /> diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java new file mode 100644 index 000000000000..0acff9bcc305 --- /dev/null +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textclassifier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; + +import android.os.LocaleList; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.view.textclassifier.TextClassificationManager; +import android.view.textclassifier.TextClassificationResult; +import android.view.textclassifier.TextClassifier; +import android.view.textclassifier.TextLanguage; +import android.view.textclassifier.TextSelection; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; +import java.util.Locale; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TextClassificationManagerTest { + + private static final LocaleList LOCALES = LocaleList.forLanguageTags("en"); + + private TextClassificationManager mTcm; + private TextClassifier mClassifier; + + @Before + public void setup() { + mTcm = InstrumentationRegistry.getTargetContext() + .getSystemService(TextClassificationManager.class); + mTcm.setTextClassifier(null); + mClassifier = mTcm.getTextClassifier(); + } + + @Test + public void testSmartSelection() { + if (isTextClassifierDisabled()) return; + + String text = "Contact me at droid@android.com"; + String selected = "droid"; + String suggested = "droid@android.com"; + int startIndex = text.indexOf(selected); + int endIndex = startIndex + selected.length(); + int smartStartIndex = text.indexOf(suggested); + int smartEndIndex = smartStartIndex + suggested.length(); + + assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES), + isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL)); + } + + @Test + public void testSmartSelection_url() { + if (isTextClassifierDisabled()) return; + + String text = "Visit http://www.android.com for more information"; + String selected = "http"; + String suggested = "http://www.android.com"; + int startIndex = text.indexOf(selected); + int endIndex = startIndex + selected.length(); + int smartStartIndex = text.indexOf(suggested); + int smartEndIndex = smartStartIndex + suggested.length(); + + assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES), + isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL)); + } + + @Test + public void testTextClassificationResult() { + if (isTextClassifierDisabled()) return; + + String text = "Contact me at droid@android.com"; + String classifiedText = "droid@android.com"; + int startIndex = text.indexOf(classifiedText); + int endIndex = startIndex + classifiedText.length(); + assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES), + isTextClassificationResult(classifiedText, TextClassifier.TYPE_EMAIL)); + } + + @Test + public void testTextClassificationResult_url() { + if (isTextClassifierDisabled()) return; + + String text = "Visit http://www.android.com for more information"; + String classifiedText = "http://www.android.com"; + int startIndex = text.indexOf(classifiedText); + int endIndex = startIndex + classifiedText.length(); + assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES), + isTextClassificationResult(classifiedText, TextClassifier.TYPE_URL)); + } + + @Test + public void testLanguageDetection() { + if (isTextClassifierDisabled()) return; + + String text = "This is a piece of English text"; + assertThat(mTcm.detectLanguages(text), isDetectedLanguage("en")); + + text = "Das ist ein deutscher Text"; + assertThat(mTcm.detectLanguages(text), isDetectedLanguage("de")); + + text = "これは日本語のテキストです"; + assertThat(mTcm.detectLanguages(text), isDetectedLanguage("ja")); + } + + @Test + public void testSetTextClassifier() { + TextClassifier classifier = mock(TextClassifier.class); + mTcm.setTextClassifier(classifier); + assertEquals(classifier, mTcm.getTextClassifier()); + } + + private boolean isTextClassifierDisabled() { + return mClassifier == TextClassifier.NO_OP; + } + + private static Matcher<TextSelection> isTextSelection( + final int startIndex, final int endIndex, final String type) { + return new BaseMatcher<TextSelection>() { + @Override + public boolean matches(Object o) { + if (o instanceof TextSelection) { + TextSelection selection = (TextSelection) o; + return startIndex == selection.getSelectionStartIndex() + && endIndex == selection.getSelectionEndIndex() + && selection.getEntityCount() > 0 + && type.equals(selection.getEntity(0)); + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendValue( + String.format("%d, %d, %s", startIndex, endIndex, type)); + } + }; + } + + private static Matcher<TextClassificationResult> isTextClassificationResult( + final String text, final String type) { + return new BaseMatcher<TextClassificationResult>() { + @Override + public boolean matches(Object o) { + if (o instanceof TextClassificationResult) { + TextClassificationResult result = (TextClassificationResult) o; + return text.equals(result.getText()) + && result.getEntityCount() > 0 + && type.equals(result.getEntity(0)); + // TODO: Include other properties. + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText("text=").appendValue(text) + .appendText(", type=").appendValue(type); + } + }; + } + + private static Matcher<List<TextLanguage>> isDetectedLanguage(final String language) { + return new BaseMatcher<List<TextLanguage>>() { + @Override + public boolean matches(Object o) { + if (o instanceof List) { + List languages = (List) o; + if (!languages.isEmpty()) { + Object o1 = languages.get(0); + if (o1 instanceof TextLanguage) { + TextLanguage lang = (TextLanguage) o1; + return lang.getLanguageCount() > 0 + && new Locale(language).getLanguage() + .equals(lang.getLanguage(0).getLanguage()); + } + } + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendValue(String.format("%s", language)); + } + }; + } +} diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index 3029134251dd..2203b6abb8fd 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -28,6 +28,7 @@ import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; import static android.widget.espresso.TextViewAssertions.hasSelection; +import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; @@ -46,6 +47,11 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.is; +import android.view.ActionMode; +import android.view.Menu; +import android.view.MenuItem; +import android.view.textclassifier.TextClassificationManager; +import android.view.textclassifier.TextClassifier; import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider; import android.support.test.espresso.action.EspressoKey; @@ -71,7 +77,8 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV @Override public void setUp() throws Exception { super.setUp(); - getActivity(); + getActivity().getSystemService(TextClassificationManager.class) + .setTextClassifier(TextClassifier.NO_OP); } public void testTypedTextIsOnScreen() throws Exception { @@ -676,4 +683,38 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV // hasTransientState should return false when selection is created by API. assertFalse(textView.hasTransientState()); } + + public void testAssistItemIsAtIndexZero() throws Exception { + getActivity().getSystemService(TextClassificationManager.class).setTextClassifier(null); + final TextView textView = (TextView) getActivity().findViewById(R.id.textview); + textView.post(() -> textView.setCustomSelectionActionModeCallback( + new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { + // Create another item at order position 0 to confirm that it will never be + // placed before the textAssist item. + menu.add(Menu.NONE, 0 /* id */, 0 /* order */, "Test"); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode actionMode) {} + })); + final String text = "droid@android.com"; + + onView(withId(R.id.textview)).perform(replaceText(text)); + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@'))); + sleepForFloatingToolbarPopup(); + assertFloatingToolbarItemIndex(android.R.id.textAssist, 0); + } } diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java index 838f4db76165..5206c9b553a6 100644 --- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java +++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java @@ -29,7 +29,13 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.is; +import android.view.MenuItem; +import android.view.ViewGroup; +import java.util.ArrayList; +import java.util.List; +import org.hamcrest.Description; import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; @@ -123,6 +129,39 @@ public class FloatingToolbarEspressoUtils { } /** + * Asserts that the floating toolbar contains a specified item at a specified index. + * + * @param menuItemId id of the menu item + * @param index expected index of the menu item in the floating toolbar + * @throws AssertionError if the assertion fails + */ + public static void assertFloatingToolbarItemIndex(final int menuItemId, final int index) { + onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() { + private List<Integer> menuItemIds = new ArrayList<>(); + + @Override + public boolean matchesSafely(View view) { + collectMenuItemIds(view); + return menuItemIds.size() > index && menuItemIds.get(index) == menuItemId; + } + + @Override + public void describeTo(Description description) {} + + private void collectMenuItemIds(View view) { + if (view.getTag() instanceof MenuItem) { + menuItemIds.add(((MenuItem) view.getTag()).getItemId()); + } else if (view instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) view; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + collectMenuItemIds(viewGroup.getChildAt(i)); + } + } + } + })); + } + + /** * Asserts that the floating toolbar doesn't contain the specified item. * * @param itemLabel label of the item. diff --git a/core/tests/overlaytests/OverlayAppFiltered/Android.mk b/core/tests/overlaytests/OverlayAppFiltered/Android.mk new file mode 100644 index 000000000000..8ba21df189f0 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_JAVA_LIBRARIES += legacy-test + +LOCAL_SDK_VERSION := system_current + +LOCAL_PACKAGE_NAME := com.android.overlaytest.filtered_app_overlay + +include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/OverlayAppFiltered/AndroidManifest.xml b/core/tests/overlaytests/OverlayAppFiltered/AndroidManifest.xml new file mode 100644 index 000000000000..5b7950a25fbf --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/AndroidManifest.xml @@ -0,0 +1,9 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.overlaytest.filtered_app_overlay" + android:versionCode="1" + android:versionName="1.0"> + <overlay android:targetPackage="com.android.overlaytest" + android:requiredSystemPropertyName="persist.oem.overlay.test" + android:requiredSystemPropertyValue="foo" + android:priority="3"/> +</manifest> diff --git a/core/tests/overlaytests/OverlayAppFiltered/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayAppFiltered/res/raw/lorem_ipsum.txt new file mode 100644 index 000000000000..0954cedeb5d5 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/res/raw/lorem_ipsum.txt @@ -0,0 +1 @@ +Lorem ipsum: filtered overlays. diff --git a/core/tests/overlaytests/OverlayAppFiltered/res/values/config.xml b/core/tests/overlaytests/OverlayAppFiltered/res/values/config.xml new file mode 100644 index 000000000000..60b94eec5994 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/res/values/config.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="str">filtered</string> +</resources> diff --git a/core/tests/overlaytests/OverlayAppFiltered/res/xml/integer.xml b/core/tests/overlaytests/OverlayAppFiltered/res/xml/integer.xml new file mode 100644 index 000000000000..e2652b7e2915 --- /dev/null +++ b/core/tests/overlaytests/OverlayAppFiltered/res/xml/integer.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?> +<integer value="3"/> diff --git a/core/tests/overlaytests/OverlayAppFirst/Android.mk b/core/tests/overlaytests/OverlayAppFirst/Android.mk index ee991fcd919a..51f4487fb25f 100644 --- a/core/tests/overlaytests/OverlayAppFirst/Android.mk +++ b/core/tests/overlaytests/OverlayAppFirst/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_JAVA_LIBRARIES += legacy-test LOCAL_SDK_VERSION := current diff --git a/core/tests/overlaytests/OverlayAppSecond/Android.mk b/core/tests/overlaytests/OverlayAppSecond/Android.mk index 87402c43dd9a..b3cfd1817cbf 100644 --- a/core/tests/overlaytests/OverlayAppSecond/Android.mk +++ b/core/tests/overlaytests/OverlayAppSecond/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_JAVA_LIBRARIES += legacy-test LOCAL_SDK_VERSION := current diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk index 4767e52c0816..964348fab881 100644 --- a/core/tests/overlaytests/OverlayTest/Android.mk +++ b/core/tests/overlaytests/OverlayTest/Android.mk @@ -7,6 +7,8 @@ LOCAL_PACKAGE_NAME := OverlayTest LOCAL_DEX_PREOPT := false +LOCAL_JAVA_LIBRARIES += legacy-test + LOCAL_MODULE_PATH := $(TARGET_OUT)/app LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/core/tests/overlaytests/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/OverlayTestOverlay/Android.mk index b1327f713ae7..5265d9169f7f 100644 --- a/core/tests/overlaytests/OverlayTestOverlay/Android.mk +++ b/core/tests/overlaytests/OverlayTestOverlay/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_JAVA_LIBRARIES += legacy-test LOCAL_SDK_VERSION := current diff --git a/core/tests/overlaytests/testrunner.py b/core/tests/overlaytests/testrunner.py index 2aa25adeda5d..e88805e8cbf1 100755 --- a/core/tests/overlaytests/testrunner.py +++ b/core/tests/overlaytests/testrunner.py @@ -13,6 +13,7 @@ TASK_COMPILATION = 'compile' TASK_DISABLE_OVERLAYS = 'disable overlays' TASK_ENABLE_MULTIPLE_OVERLAYS = 'enable multiple overlays' TASK_ENABLE_SINGLE_OVERLAY = 'enable single overlay' +TASK_ENABLE_FILTERED_OVERLAYS = 'enable filtered overlays' TASK_FILE_EXISTS_TEST = 'test (file exists)' TASK_GREP_IDMAP_TEST = 'test (grep idmap)' TASK_MD5_TEST = 'test (md5)' @@ -25,6 +26,7 @@ TASK_PUSH = 'push' TASK_ROOT = 'root' TASK_REMOUNT = 'remount' TASK_RM = 'rm' +TASK_SETPROP = 'setprop' TASK_SETUP_IDMAP_PATH = 'setup idmap --path' TASK_SETUP_IDMAP_SCAN = 'setup idmap --scan' TASK_START = 'start' @@ -188,7 +190,10 @@ class PushTask: return "%s -> %s" % (self.src, self.dest) def execute(self): - src = os.getenv('OUT') + "/" + self.src + src = os.getenv('OUT') + if (src is None): + return 1, "", "Unable to proceed - $OUT environment var not set\n" + src += "/" + self.src argv = shlex.split(adb + ' push %s %s' % (src, self.dest)) proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = proc.communicate() @@ -219,10 +224,24 @@ class RmTask: def execute(self): returncode, stdout, stderr = _adb_shell('ls %s' % self.path) - if returncode != 0 and stdout.endswith(': No such file or directory\n'): + if returncode != 0 and stderr.endswith(': No such file or directory\n'): return 0, "", "" return _adb_shell('rm -r %s' % self.path) +class SetPropTask: + def __init__(self, prop, value): + self.prop = prop + self.value = value + + def get_type(self): + return TASK_SETPROP + + def get_name(self): + return self.prop + + def execute(self): + return _adb_shell('setprop %s %s' % (self.prop, self.value)) + class IdmapPathTask: def __init__(self, path_target_apk, path_overlay_apk, path_idmap): self.path_target_apk = path_target_apk @@ -236,7 +255,7 @@ class IdmapPathTask: return self.path_idmap def execute(self): - return _adb_shell('su system idmap --path "%s" "%s" "%s"' % (self.path_target_apk, self.path_overlay_apk, self.path_idmap)) + return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.target_pkg_name, self.target_pkg, self.idmap_dir, self.overlay_dir)) class IdmapScanTask: def __init__(self, overlay_dir, target_pkg_name, target_pkg, idmap_dir, symlink_dir): @@ -411,8 +430,12 @@ def _create_disable_overlays_task(): RmTask("/data/resource-cache/vendor@overlay@framework_b.apk@idmap"), RmTask("/vendor/overlay/app_a.apk"), RmTask("/vendor/overlay/app_b.apk"), + RmTask("/vendor/overlay/app_c.apk"), RmTask("/data/resource-cache/vendor@overlay@app_a.apk@idmap"), RmTask("/data/resource-cache/vendor@overlay@app_b.apk@idmap"), + RmTask("/data/resource-cache/vendor@overlay@app_c.apk@idmap"), + SetPropTask('persist.oem.overlay.test', '""'), + RmTask("/data/property/persist.oem.overlay.test"), ] return CompoundTask(TASK_DISABLE_OVERLAYS, tasks) @@ -435,9 +458,23 @@ def _create_enable_multiple_overlays_task(): PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'), PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'), PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'), + PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'), ] return CompoundTask(TASK_ENABLE_MULTIPLE_OVERLAYS, tasks) +def _create_enable_filtered_overlays_task(): + tasks = [ + _create_disable_overlays_task(), + SetPropTask('persist.oem.overlay.test', 'foo'), + MkdirTask('/system/vendor'), + MkdirTask('/vendor/overlay'), + PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'), + PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'), + PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'), + PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'), + ] + return CompoundTask(TASK_ENABLE_FILTERED_OVERLAYS, tasks) + def _create_setup_idmap_path_task(idmaps, symlinks): tasks = [ _create_enable_single_overlay_task(), @@ -450,12 +487,11 @@ def _create_setup_idmap_path_task(idmaps, symlinks): def _create_setup_idmap_scan_task(idmaps, symlinks): tasks = [ - _create_enable_single_overlay_task(), + _create_enable_filtered_overlays_task(), RmTask(symlinks), RmTask(idmaps), MkdirTask(idmaps), MkdirTask(symlinks), - _create_enable_multiple_overlays_task(), ] return CompoundTask(TASK_SETUP_IDMAP_SCAN, tasks) @@ -538,7 +574,7 @@ def _create_opt_parser(): help='do not rebuild test projects') parser.add_option('-i', '--test-idmap', action='store_true', dest='test_idmap', default=False, - help='run tests for single overlay') + help='run tests for idmap') parser.add_option('-0', '--test-no-overlay', action='store_true', dest='test_no_overlay', default=False, help='run tests without any overlay') @@ -548,16 +584,21 @@ def _create_opt_parser(): parser.add_option('-2', '--test-multiple-overlays', action='store_true', dest='test_multiple_overlays', default=False, help='run tests for multiple overlays') + parser.add_option('-3', '--test-filtered-overlays', action='store_true', + dest='test_filtered_overlays', default=False, + help='run tests for filtered (sys prop) overlays') return parser if __name__ == '__main__': opt_parser = _create_opt_parser() opts, args = opt_parser.parse_args(sys.argv[1:]) - if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays: + if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays and not opts.test_filtered_overlays: opts.test_idmap = True opts.test_no_overlay = True opts.test_single_overlay = True opts.test_multiple_overlays = True + opts.test_filtered_overlays = True + if len(args) > 0: opt_parser.error("unexpected arguments: %s" % " ".join(args)) # will never reach this: opt_parser.error will call sys.exit @@ -580,6 +621,7 @@ if __name__ == '__main__': tasks.append(CompilationTask('OverlayTestOverlay/Android.mk')) tasks.append(CompilationTask('OverlayAppFirst/Android.mk')) tasks.append(CompilationTask('OverlayAppSecond/Android.mk')) + tasks.append(CompilationTask('OverlayAppFiltered/Android.mk')) # remount filesystem, install test project tasks.append(RootTask()) @@ -600,13 +642,13 @@ if __name__ == '__main__': tasks.append(GrepIdmapTest(idmaps + '/a.idmap', 'bool/config_annoy_dianne', 1)) # idmap --scan - idmap = idmaps + '/vendor@overlay@framework_b.apk@idmap' tasks.append(StopTask()) tasks.append(_create_setup_idmap_scan_task(idmaps, symlinks)) tasks.append(StartTask()) tasks.append(IdmapScanTask('/vendor/overlay', 'android', '/system/framework/framework-res.apk', idmaps, symlinks)) - tasks.append(FileExistsTest(idmap)) - tasks.append(GrepIdmapTest(idmap, 'bool/config_annoy_dianne', 1)) + tasks.append(FileExistsTest(idmaps + '/vendor@overlay@framework_b.apk@idmap')) + tasks.append(GrepIdmapTest(idmaps + '/vendor@overlay@framework_b.apk@idmap', 'bool/config_annoy_dianne', 1)) + # overlays.list overlays_list_path = idmaps + '/overlays.list' @@ -620,27 +662,38 @@ if __name__ == '__main__': tasks.append(RmTask(symlinks)) tasks.append(RmTask(idmaps)) - # test no overlay + # test no overlay: all overlays cleared if opts.test_no_overlay: tasks.append(StopTask()) tasks.append(_create_disable_overlays_task()) tasks.append(StartTask()) tasks.append(InstrumentationTask('com.android.overlaytest.WithoutOverlayTest')) - # test single overlay + # test single overlay: one overlay (a) if opts.test_single_overlay: tasks.append(StopTask()) tasks.append(_create_enable_single_overlay_task()) tasks.append(StartTask()) tasks.append(InstrumentationTask('com.android.overlaytest.WithOverlayTest')) - # test multiple overlays + # test multiple overlays: all overlays - including 'disabled' filtered + # overlay (system property unset) so expect 'b[p=2]' overrides 'a[p=1]' but + # 'c[p=3]' should be ignored if opts.test_multiple_overlays: tasks.append(StopTask()) tasks.append(_create_enable_multiple_overlays_task()) tasks.append(StartTask()) tasks.append(InstrumentationTask('com.android.overlaytest.WithMultipleOverlaysTest')) + # test filtered overlays: all overlays - including 'enabled' filtered + # overlay (system property set/matched) so expect c[p=3] to override both a + # & b where applicable + if opts.test_filtered_overlays: + tasks.append(StopTask()) + tasks.append(_create_enable_filtered_overlays_task()) + tasks.append(StartTask()) + tasks.append(InstrumentationTask('com.android.overlaytest.WithFilteredOverlaysTest')) + ignored_errors = 0 for t in tasks: type = t.get_type() 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/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/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 67504cfe323b..f2957a30b05e 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1592,7 +1592,7 @@ public abstract class ColorSpace { Math.abs(a.a - b.a) < 1e-3 && Math.abs(a.b - b.b) < 1e-3 && Math.abs(a.c - b.c) < 1e-3 && - Math.abs(a.d - b.d) < 1e-3 && + Math.abs(a.d - b.d) < 2e-3 && // Special case for variations in sRGB OETF/EOTF Math.abs(a.e - b.e) < 1e-3 && Math.abs(a.f - b.f) < 1e-3 && Math.abs(a.g - b.g) < 1e-3; 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/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index 3e7a246bb281..931a55a70fd8 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -600,12 +600,12 @@ void verify(const ProgramDescription& description, const Glop& glop) { void GlopBuilder::build() { REQUIRE_STAGES(kAllStages); if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) { - if (mOutGlop->fill.texture.texture->target() == GL_TEXTURE_2D) { + Texture* texture = mOutGlop->fill.texture.texture; + if (texture->target() == GL_TEXTURE_2D) { mDescription.hasTexture = true; } else { mDescription.hasExternalTexture = true; } - Texture* texture = mOutGlop->fill.texture.texture; mDescription.hasLinearTexture = texture->isLinear(); mDescription.hasColorSpaceConversion = texture->hasColorSpaceConversion(); mDescription.transferFunction = texture->getTransferFunctionType(); diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index d95acff8a38e..3e5e3bfc3bf2 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -390,14 +390,8 @@ bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkCl } bool SkiaCanvas::clipPath(const SkPath* path, SkClipOp op) { - SkRRect roundRect; - if (path->isRRect(&roundRect)) { - this->recordClip(roundRect, op); - mCanvas->clipRRect(roundRect, op); - } else { - this->recordClip(*path, op); - mCanvas->clipPath(*path, op); - } + this->recordClip(*path, op); + mCanvas->clipPath(*path, op); return !mCanvas->isClipEmpty(); } diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp index ee202367d73e..773a7ea54a52 100644 --- a/libs/hwui/tests/unit/FontRendererTests.cpp +++ b/libs/hwui/tests/unit/FontRendererTests.cpp @@ -28,7 +28,7 @@ static bool isZero(uint8_t* data, int size) { return true; } -RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) { +RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, DISABLED_renderDropShadow) { SkPaint paint; paint.setTextSize(10); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp index 8312bda8d67d..5383e5756b93 100644 --- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp +++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp @@ -26,7 +26,7 @@ using namespace android; using namespace android::uirenderer; -RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) { +RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, DISABLED_addRemove) { SkPaint paint; paint.setTextSize(20); 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..d5efc971d1fd 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; @@ -1007,13 +1007,14 @@ public class MediaPlayer extends PlayerBase * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @param headers the headers to be sent together with the request for the data - * Note that the cross domain redirection is allowed by default, but that can be - * changed with key/value pairs through the headers parameter with - * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value - * to disallow or allow cross domain redirection. * The headers must not include cookies. Instead, use the cookies param. * @param cookies the cookies to be sent together with the request * @throws IllegalStateException if it is called in an invalid state + * + * <p><strong>Note</strong> that the cross domain redirection is allowed by default, + * but that can be changed with key/value pairs through the headers parameter with + * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to + * disallow or allow cross domain redirection. */ public void setDataSource(@NonNull Context context, @NonNull Uri uri, @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) @@ -1056,11 +1057,12 @@ public class MediaPlayer extends PlayerBase * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @param headers the headers to be sent together with the request for the data - * Note that the cross domain redirection is allowed by default, but that can be - * changed with key/value pairs through the headers parameter with - * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value - * to disallow or allow cross domain redirection. * @throws IllegalStateException if it is called in an invalid state + * + * <p><strong>Note</strong> that the cross domain redirection is allowed by default, + * but that can be changed with key/value pairs through the headers parameter with + * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to + * disallow or allow cross domain redirection. */ public void setDataSource(@NonNull Context context, @NonNull Uri uri, @Nullable Map<String, String> headers) @@ -1491,20 +1493,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. @@ -1982,7 +1983,7 @@ public class MediaPlayer extends PlayerBase mOnSubtitleDataListener = null; // Modular DRM clean up - mOnDrmConfigListener = null; + mOnDrmConfigHelper = null; mOnDrmInfoHandlerDelegate = null; mOnDrmPreparedHandlerDelegate = null; resetDrmState(); @@ -3906,11 +3907,11 @@ public class MediaPlayer extends PlayerBase * 'securityLevel', which has to be set after DRM scheme creation but * before the DRM session is opened. * - * The only allowed DRM calls in this listener are getDrmPropertyString - * and setDrmPropertyString. + * The only allowed DRM calls in this listener are {@code getDrmPropertyString} + * and {@code setDrmPropertyString}. * */ - public interface OnDrmConfigListener + public interface OnDrmConfigHelper { /** * Called to give the app the opportunity to configure DRM before the session is created @@ -3923,19 +3924,19 @@ public class MediaPlayer extends PlayerBase /** * Register a callback to be invoked for configuration of the DRM object before * the session is created. - * The callback will be invoked synchronously half-way into the execution + * The callback will be invoked synchronously during the execution * of {@link #prepareDrm(UUID uuid)}. * * @param listener the callback that will be run */ - public void setOnDrmConfigListener(OnDrmConfigListener listener) + public void setOnDrmConfigHelper(OnDrmConfigHelper listener) { synchronized (mDrmLock) { - mOnDrmConfigListener = listener; + mOnDrmConfigHelper = listener; } // synchronized } - private OnDrmConfigListener mOnDrmConfigListener; + private OnDrmConfigHelper mOnDrmConfigHelper; /** * Interface definition of a callback to be invoked when the @@ -3947,7 +3948,7 @@ public class MediaPlayer extends PlayerBase * Called to indicate DRM info is available * * @param mp the {@code MediaPlayer} associated with this callback - * @param drmInfo DRM info of the source including PSSH, mimes, and subset + * @param drmInfo DRM info of the source including PSSH, and subset * of crypto schemes supported by this device */ public void onDrmInfo(MediaPlayer mp, DrmInfo drmInfo); @@ -3983,6 +3984,41 @@ public class MediaPlayer extends PlayerBase private OnDrmInfoHandlerDelegate mOnDrmInfoHandlerDelegate; + + /** + * The status codes for {@link OnDrmPreparedListener#onDrmPrepared} listener. + * <p> + * + * DRM preparation has succeeded. + */ + public static final int PREPARE_DRM_STATUS_SUCCESS = 0; + + /** + * The device required DRM provisioning but couldn't reach the provisioning server. + */ + public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; + + /** + * The device required DRM provisioning but the provisioning server denied the request. + */ + public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; + + /** + * The DRM preparation has failed . + */ + public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; + + + /** @hide */ + @IntDef({ + PREPARE_DRM_STATUS_SUCCESS, + PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR, + PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR, + PREPARE_DRM_STATUS_PREPARATION_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PrepareDrmStatusCode {} + /** * Interface definition of a callback to notify the app when the * DRM is ready for key request/response @@ -3993,9 +4029,13 @@ public class MediaPlayer extends PlayerBase * Called to notify the app that prepareDrm is finished and ready for key request/response * * @param mp the {@code MediaPlayer} associated with this callback - * @param success the result of DRM preparation + * @param status the result of DRM preparation which can be + * {@link #PREPARE_DRM_STATUS_SUCCESS}, + * {@link #PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR}, + * {@link #PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR}, or + * {@link #PREPARE_DRM_STATUS_PREPARATION_ERROR}. */ - public void onDrmPrepared(MediaPlayer mp, boolean success); + public void onDrmPrepared(MediaPlayer mp, @PrepareDrmStatusCode int status); } /** @@ -4039,30 +4079,28 @@ public class MediaPlayer extends PlayerBase mOnDrmInfoListener = listener; // find the looper for our new event handler - Looper looper = null; if (handler != null) { - looper = handler.getLooper(); - } - - // construct the event handler with this looper - if (looper != null) { - // implement the event handler delegate - mHandler = new Handler(looper) { - public void handleMessage(Message msg) { - DrmInfo drmInfo = (DrmInfo)msg.obj; - mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo); - } - }; + mHandler = handler; + } else { + // handler == null + // Will let OnDrmInfoListener be called in mEventHandler similar to other + // legacy notifications. This is because MEDIA_DRM_INFO's notification has to be + // sent before MEDIA_PREPARED's (i.e., in the same order they are issued by + // mediaserver). As a result, the callback has to be called directly by + // EventHandler.handleMessage similar to onPrepared. } } void notifyClient(DrmInfo drmInfo) { - if ( mHandler != null ) { - Message msg = new Message(); // no message type needed - msg.obj = drmInfo; - mHandler.sendMessage(msg); + if (mHandler != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo); + } + }); } - else { // no handler: direct call + else { // no handler: direct call by mEventHandler mOnDrmInfoListener.onDrmInfo(mMediaPlayer, drmInfo); } } @@ -4079,31 +4117,26 @@ public class MediaPlayer extends PlayerBase mOnDrmPreparedListener = listener; // find the looper for our new event handler - Looper looper = null; if (handler != null) { - looper = handler.getLooper(); - } - - // construct the event handler with this looper - if (looper != null) { - // implement the event handler delegate - mHandler = new Handler(looper) { - public void handleMessage(Message msg) { - boolean success = (msg.arg1 == 0) ? false : true; - mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success); - } - }; + mHandler = handler; + } else if (mEventHandler != null) { + // Otherwise, use mEventHandler + mHandler = mEventHandler; + } else { + Log.e(TAG, "OnDrmPreparedHandlerDelegate: Unexpected null mEventHandler"); } } - void notifyClient(boolean success) { - if ( mHandler != null ) { - Message msg = new Message(); // no message type needed - msg.arg1 = success ? 1 : 0; - mHandler.sendMessage(msg); - } - else { // no handler: direct call - mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, success); + void notifyClient(int status) { + if (mHandler != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mOnDrmPreparedListener.onDrmPrepared(mMediaPlayer, status); + } + }); + } else { + Log.e(TAG, "OnDrmPreparedHandlerDelegate:notifyClient: Unexpected null mHandler"); } } } @@ -4138,7 +4171,7 @@ public class MediaPlayer extends PlayerBase /** * Prepares the DRM for the current source * <p> - * If {@code OnDrmConfigListener} is registered, it will be called half-way into + * If {@code OnDrmConfigHelper} is registered, it will be called during * preparation to allow configuration of the DRM properties before opening the * DRM session. Note that the callback is called synchronously in the thread that called * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString} @@ -4149,9 +4182,9 @@ public class MediaPlayer extends PlayerBase * complete depending on the network connectivity. * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking * mode by launching the provisioning in the background and returning. The listener - * will be called when provisioning and preperation has finished. If a + * will be called when provisioning and preparation has finished. If a * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning - * and preperation has finished, i.e., runs in blocking mode. + * and preparation has finished, i.e., runs in blocking mode. * <p> * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM * session being ready. The application should not make any assumption about its call @@ -4159,18 +4192,23 @@ public class MediaPlayer extends PlayerBase * execute the listener (unless the listener is registered with a handler thread). * <p> * - * @param uuid The UUID of the crypto scheme. + * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved + * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}. * - * @throws IllegalStateException if called before prepare(), or there exists a Drm already - * @throws UnsupportedSchemeException if the crypto scheme is not supported - * @throws ResourceBusyException if required DRM resources are in use - * @throws ProvisioningErrorException if provisioning is required but an attempt failed + * @throws IllegalStateException if called before prepare(), or the DRM was + * prepared already + * @throws UnsupportedSchemeException if the crypto scheme is not supported + * @throws ResourceBusyException if required DRM resources are in use + * @throws ProvisioningNetworkErrorException if provisioning is required but failed due to a + * network error + * @throws ProvisioningServerErrorException if provisioning is required but failed due to + * the request denied by the provisioning server */ public void prepareDrm(@NonNull UUID uuid) - throws UnsupportedSchemeException, - ResourceBusyException, ProvisioningErrorException + throws UnsupportedSchemeException, ResourceBusyException, + ProvisioningNetworkErrorException, ProvisioningServerErrorException { - Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigListener: " + mOnDrmConfigListener); + Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper); boolean allDoneWithoutProvisioning = false; // get a snapshot as we'll use them outside the lock @@ -4178,7 +4216,7 @@ public class MediaPlayer extends PlayerBase synchronized (mDrmLock) { - // only allowing if tied to a protected source; might releax for releasing offline keys + // only allowing if tied to a protected source; might relax for releasing offline keys if (mDrmInfo == null) { final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " + "DRM info be retrieved before this call."; @@ -4227,8 +4265,8 @@ public class MediaPlayer extends PlayerBase // call the callback outside the lock - if (mOnDrmConfigListener != null) { - mOnDrmConfigListener.onDrmConfig(this); + if (mOnDrmConfigHelper != null) { + mOnDrmConfigHelper.onDrmConfig(this); } synchronized (mDrmLock) { @@ -4252,15 +4290,33 @@ public class MediaPlayer extends PlayerBase Log.w(TAG, "prepareDrm: NotProvisionedException"); // handle provisioning internally; it'll reset mPrepareDrmInProgress - boolean result = HandleProvisioninig(uuid); + int result = HandleProvisioninig(uuid); // if blocking mode, we're already done; // if non-blocking mode, we attempted to launch background provisioning - if (result == false) { - final String msg = "prepareDrm: Provisioning was required but failed."; - Log.e(TAG, msg); + if (result != PREPARE_DRM_STATUS_SUCCESS) { earlyExit = true; - throw new ProvisioningErrorException(msg); + String msg; + + switch (result) { + case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR: + msg = "prepareDrm: Provisioning was required but failed " + + "due to a network error."; + Log.e(TAG, msg); + throw new ProvisioningNetworkErrorException(msg); + + case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR: + msg = "prepareDrm: Provisioning was required but the request " + + "was denied by the server."; + Log.e(TAG, msg); + throw new ProvisioningServerErrorException(msg); + + case PREPARE_DRM_STATUS_PREPARATION_ERROR: + default: // default for safeguard + msg = "prepareDrm: Post-provisioning preparation failed."; + Log.e(TAG, msg); + throw new IllegalStateException(msg); + } } // nothing else to do; // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup @@ -4282,7 +4338,7 @@ public class MediaPlayer extends PlayerBase // if finished successfully without provisioning, call the callback outside the lock if (allDoneWithoutProvisioning) { if (onDrmPreparedHandlerDelegate != null) - onDrmPreparedHandlerDelegate.notifyClient(true /*success*/); + onDrmPreparedHandlerDelegate.notifyClient(PREPARE_DRM_STATUS_SUCCESS); } } @@ -4292,6 +4348,10 @@ public class MediaPlayer extends PlayerBase /** * Releases the DRM session + * <p> + * The player has to have an active DRM session and be in stopped, or prepared + * state before this call is made. + * A {@code reset()} call will release the DRM session implicitly. * * @throws NoDrmSchemeException if there is no active DRM session to release */ @@ -4308,7 +4368,7 @@ public class MediaPlayer extends PlayerBase try { // we don't have the player's state in this layer. The below call raises - // exception if we're in a non-stopped/idle state. + // exception if we're in a non-stopped/prepared state. // for cleaning native/mediaserver crypto object _releaseDrm(); @@ -4317,9 +4377,11 @@ public class MediaPlayer extends PlayerBase cleanDrmObj(); mActiveDrmScheme = false; - } catch (Exception e) { + } catch (IllegalStateException e) { Log.w(TAG, "releaseDrm: Exception ", e); - throw e; + throw new IllegalStateException("releaseDrm: The player is not in a valid state."); + } catch (Exception e) { + Log.e(TAG, "releaseDrm: Exception ", e); } } // synchronized } @@ -4338,21 +4400,23 @@ public class MediaPlayer extends PlayerBase * it should deliver to the response to the DRM engine plugin using the method * {@link #provideKeyResponse}. * - * @param scope may be a container-specific initialization data or a keySetId, - * depending on the specified keyType. - * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, scope should be set to - * the container-specific initialization data. Its meaning is interpreted based on the - * mime type provided in the mimeType parameter. It could contain, for example, - * the content ID, key ID or other data obtained from the content metadata that is - * required in generating the key request. - * When the keyType is KEY_TYPE_RELEASE, scope should be set to the keySetId of - * the keys being released. + * @param keySetId is the key-set identifier of the offline keys being released when keyType is + * {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when + * keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. + * + * @param initData is the container-specific initialization data when the keyType is + * {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is + * interpreted based on the mime type provided in the mimeType parameter. It could + * contain, for example, the content ID, key ID or other data obtained from the content + * metadata that is required in generating the key request. + * When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null. * * @param mimeType identifies the mime type of the content * - * @param keyType specifes the type of the request. The request may be to acquire - * keys for streaming or offline content, or to release previously acquired - * keys, which are identified by a keySetId. + * @param keyType specifies the type of the request. The request may be to acquire + * keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content + * {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired + * keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId. * * @param optionalParameters are included in the key request message to * allow a client application to provide additional message parameters to the server. @@ -4361,12 +4425,13 @@ public class MediaPlayer extends PlayerBase * @throws NoDrmSchemeException if there is no active DRM session */ @NonNull - public MediaDrm.KeyRequest getKeyRequest(@NonNull byte[] scope, @Nullable String mimeType, - @MediaDrm.KeyType int keyType, @Nullable Map<String, String> optionalParameters) + public MediaDrm.KeyRequest getKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData, + @Nullable String mimeType, @MediaDrm.KeyType int keyType, + @Nullable Map<String, String> optionalParameters) throws NoDrmSchemeException { Log.v(TAG, "getKeyRequest: " + - " scope: " + scope + " mimeType: " + mimeType + + " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType + " keyType: " + keyType + " optionalParameters: " + optionalParameters); synchronized (mDrmLock) { @@ -4376,20 +4441,16 @@ public class MediaPlayer extends PlayerBase } try { - byte[] scopeOut = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? - mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE - scope; // keySetId for KEY_TYPE_RELEASE - - byte[] initData = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? - scope : // initData for KEY_TYPE_STREAMING/OFFLINE - null; // not used for KEY_TYPE_RELEASE + byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? + mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE + keySetId; // keySetId for KEY_TYPE_RELEASE HashMap<String, String> hmapOptionalParameters = (optionalParameters != null) ? new HashMap<String, String>(optionalParameters) : null; - MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scopeOut, initData, mimeType, + MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scope, initData, mimeType, keyType, hmapOptionalParameters); Log.v(TAG, "getKeyRequest: --> request: " + request); @@ -4500,8 +4561,8 @@ public class MediaPlayer extends PlayerBase * @param propertyName the property name * * Standard fields names are: - * {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION}, - * {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS} + * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION}, + * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS} */ @NonNull public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName) @@ -4538,8 +4599,8 @@ public class MediaPlayer extends PlayerBase * @param value the property value * * Standard fields names are: - * {link #PROPERTY_VENDOR}, {link #PROPERTY_VERSION}, - * {link #PROPERTY_DESCRIPTION}, {link #PROPERTY_ALGORITHMS} + * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION}, + * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS} */ public void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName, @NonNull String value) @@ -4566,8 +4627,6 @@ public class MediaPlayer extends PlayerBase public static final class DrmInfo { private Map<UUID, byte[]> mapPssh; private UUID[] supportedSchemes; - // TODO: Won't need this in final release. Only keeping it for the existing test app. - private String[] mimes; public Map<UUID, byte[]> getPssh() { return mapPssh; @@ -4575,15 +4634,10 @@ public class MediaPlayer extends PlayerBase public UUID[] getSupportedSchemes() { return supportedSchemes; } - // TODO: Won't need this in final release. Only keeping it for the existing test app. - public String[] getMimes() { - return mimes; - } - private DrmInfo(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes, String[] Mimes) { + private DrmInfo(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes) { mapPssh = Pssh; supportedSchemes = SupportedSchemes; - mimes = Mimes; } private DrmInfo(Parcel parcel) { @@ -4609,18 +4663,12 @@ public class MediaPlayer extends PlayerBase supportedSchemes[i]); } - // TODO: Won't need this in final release. Only keeping it for the test app. - mimes = parcel.readStringArray(); - int mimeCount = mimes.length; - Log.v(TAG, "DrmInfo() mime: " + Arrays.toString(mimes)); - Log.v(TAG, "DrmInfo() Parcel psshsize: " + psshsize + - " supportedDRMsCount: " + supportedDRMsCount + - " mimeCount: " + mimeCount); + " supportedDRMsCount: " + supportedDRMsCount); } private DrmInfo makeCopy() { - return new DrmInfo(this.mapPssh, this.supportedSchemes, this.mimes); + return new DrmInfo(this.mapPssh, this.supportedSchemes); } private String arrToHex(byte[] bytes) { @@ -4715,11 +4763,22 @@ public class MediaPlayer extends PlayerBase /** * Thrown when the device requires DRM provisioning but the provisioning attempt has - * failed (for example: network timeout, provisioning server error). + * failed due to a network error (Internet reachability, timeout, etc.). * Extends MediaDrm.MediaDrmException */ - public static final class ProvisioningErrorException extends MediaDrmException { - public ProvisioningErrorException(String detailMessage) { + public static final class ProvisioningNetworkErrorException extends MediaDrmException { + public ProvisioningNetworkErrorException(String detailMessage) { + super(detailMessage); + } + } + + /** + * Thrown when the device requires DRM provisioning but the provisioning attempt has + * failed due to the provisioning server denying the request. + * Extends MediaDrm.MediaDrmException + */ + public static final class ProvisioningServerErrorException extends MediaDrmException { + public ProvisioningServerErrorException(String detailMessage) { super(detailMessage); } } @@ -4771,14 +4830,13 @@ public class MediaPlayer extends PlayerBase private UUID uuid; private String urlStr; - private byte[] response; private Object drmLock; private OnDrmPreparedHandlerDelegate onDrmPreparedHandlerDelegate; private MediaPlayer mediaPlayer; - private boolean succeeded; + private int status; private boolean finished; - public boolean succeeded() { - return succeeded; + public int status() { + return status; } public ProvisioningThread initialize(MediaDrm.ProvisionRequest request, @@ -4791,12 +4849,15 @@ public class MediaPlayer extends PlayerBase urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData()); this.uuid = uuid; + status = PREPARE_DRM_STATUS_PREPARATION_ERROR; + Log.v(TAG, "HandleProvisioninig: Thread is initialised url: " + urlStr); return this; } public void run() { + byte[] response = null; boolean provisioningSucceeded = false; try { URL url = new URL(urlStr); @@ -4814,11 +4875,13 @@ public class MediaPlayer extends PlayerBase Log.v(TAG, "HandleProvisioninig: Thread run: response " + response.length + " " + response); } catch (Exception e) { + status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR; Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url); } finally { connection.disconnect(); } } catch (Exception e) { + status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR; Log.w(TAG, "HandleProvisioninig: Thread run: openConnection " + e); } @@ -4829,12 +4892,15 @@ public class MediaPlayer extends PlayerBase "provideProvisionResponse SUCCEEDED!"); provisioningSucceeded = true; - } catch (Exception e) { + } catch (Exception e) { + status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR; Log.w(TAG, "HandleProvisioninig: Thread run: " + "provideProvisionResponse " + e); } } + boolean succeeded = false; + // non-blocking mode needs the lock if (onDrmPreparedHandlerDelegate != null) { @@ -4842,6 +4908,9 @@ public class MediaPlayer extends PlayerBase // continuing with prepareDrm if (provisioningSucceeded) { succeeded = mediaPlayer.resumePrepareDrm(uuid); + status = (succeeded) ? + PREPARE_DRM_STATUS_SUCCESS : + PREPARE_DRM_STATUS_PREPARATION_ERROR; } mediaPlayer.mDrmProvisioningInProgress = false; mediaPlayer.mPrepareDrmInProgress = false; @@ -4851,12 +4920,15 @@ public class MediaPlayer extends PlayerBase } // synchronized // calling the callback outside the lock - onDrmPreparedHandlerDelegate.notifyClient(succeeded); + onDrmPreparedHandlerDelegate.notifyClient(status); } else { // blocking mode already has the lock // continuing with prepareDrm if (provisioningSucceeded) { succeeded = mediaPlayer.resumePrepareDrm(uuid); + status = (succeeded) ? + PREPARE_DRM_STATUS_SUCCESS : + PREPARE_DRM_STATUS_PREPARATION_ERROR; } mediaPlayer.mDrmProvisioningInProgress = false; mediaPlayer.mPrepareDrmInProgress = false; @@ -4870,19 +4942,19 @@ public class MediaPlayer extends PlayerBase } // ProvisioningThread - private boolean HandleProvisioninig(UUID uuid) + private int HandleProvisioninig(UUID uuid) { // the lock is already held by the caller if (mDrmProvisioningInProgress) { Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress"); - return false; + return PREPARE_DRM_STATUS_PREPARATION_ERROR; } MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest(); if (provReq == null) { Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null."); - return false; + return PREPARE_DRM_STATUS_PREPARATION_ERROR; } Log.v(TAG, "HandleProvisioninig provReq " + @@ -4894,11 +4966,11 @@ public class MediaPlayer extends PlayerBase mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this); mDrmProvisioningThread.start(); - boolean result = false; + int result; - // non-blocking + // non-blocking: this is not the final result if (mOnDrmPreparedHandlerDelegate != null) { - result = true; + result = PREPARE_DRM_STATUS_SUCCESS; } else { // if blocking mode, wait till provisioning is done try { @@ -4906,7 +4978,7 @@ public class MediaPlayer extends PlayerBase } catch (Exception e) { Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e); } - result = mDrmProvisioningThread.succeeded(); + result = mDrmProvisioningThread.status(); // no longer need the thread mDrmProvisioningThread = null; } @@ -5418,4 +5490,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..997d56222ff7 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -20,14 +20,15 @@ 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; +import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.RandomAccessFile; @@ -92,6 +93,7 @@ public class MediaRecorder private String mPath; private FileDescriptor mFd; + private File mFile; private EventHandler mEventHandler; private OnErrorListener mOnErrorListener; private OnInfoListener mOnInfoListener; @@ -804,10 +806,26 @@ public class MediaRecorder public void setOutputFile(FileDescriptor fd) throws IllegalStateException { mPath = null; + mFile = null; mFd = fd; } /** + * Pass in the file object to be written. Call this after setOutputFormat() but before prepare(). + * File should be seekable. After setting the next output file, application should not use the + * file until {@link #stop}. Application is responsible for cleaning up unused files after + * {@link #stop} is called. + * + * @param file the file object to be written into. + */ + public void setOutputFile(File file) + { + mPath = null; + mFd = null; + mFile = file; + } + + /** * Sets the next output file descriptor to be used when the maximum filesize is reached * on the prior output {@link #setOutputFile} or {@link #setNextOutputFile}). File descriptor * must be seekable and writable. After setting the next output file, application should not @@ -842,15 +860,16 @@ public class MediaRecorder public void setOutputFile(String path) throws IllegalStateException { mFd = null; + mFile = null; mPath = path; } /** - * Sets the next output file path to be used when the maximum filesize is reached - * on the prior output {@link #setOutputFile} or {@link #setNextOutputFile}). File should - * be seekable. After setting the next output file, application should not use the file - * referenced by this file descriptor until {@link #stop}. Application must call this - * after receiving on the {@link android.media.MediaRecorder.OnInfoListener} a "what" code of + * Sets the next output file to be used when the maximum filesize is reached on the prior + * output {@link #setOutputFile} or {@link #setNextOutputFile}). File should be seekable. + * After setting the next output file, application should not use the file until {@link #stop}. + * Application must call this after receiving on the + * {@link android.media.MediaRecorder.OnInfoListener} a "what" code of * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING} and before receiving a "what" code of * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}. The file is not used until switching to * that output. Application will receive {@link #MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED} @@ -858,19 +877,17 @@ public class MediaRecorder * the previous one has not been used. Application is responsible for cleaning up unused files * after {@link #stop} is called. * - * @param path The pathname to use. + * @param file The file to use. * @throws IllegalStateException if it is called before prepare(). * @throws IOException if setNextOutputFile fails otherwise. */ - public void setNextOutputFile(String path) throws IllegalStateException, IOException + public void setNextOutputFile(File file) throws IllegalStateException, IOException { - if (path != null) { - RandomAccessFile file = new RandomAccessFile(path, "rws"); - try { - _setNextOutputFile(file.getFD()); - } finally { - file.close(); - } + RandomAccessFile f = new RandomAccessFile(file, "rws"); + try { + _setNextOutputFile(f.getFD()); + } finally { + f.close(); } } @@ -899,6 +916,13 @@ public class MediaRecorder } } else if (mFd != null) { _setOutputFile(mFd); + } else if (mFile != null) { + RandomAccessFile file = new RandomAccessFile(mFile, "rws"); + try { + _setOutputFile(file.getFD()); + } finally { + file.close(); + } } else { throw new IOException("No valid output file"); } @@ -1267,23 +1291,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/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 5bf205e12799..789d5e0d8478 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -365,7 +365,7 @@ public final class MediaBrowser { * @param parentId The id of the parent media item whose list of children * will be subscribed. * @param options The bundle of service-specific arguments to send to the media - * browse service. The contents of this bundle may affect the + * browser service. The contents of this bundle may affect the * information returned when browsing. * @param callback The callback to receive the list of children. */ @@ -453,7 +453,7 @@ public final class MediaBrowser { try { mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks); } catch (RemoteException e) { - Log.i(TAG, "Remote error getting media item.", e); + Log.i(TAG, "Remote error getting media item."); mHandler.post(new Runnable() { @Override public void run() { @@ -463,62 +463,6 @@ public final class MediaBrowser { } } - /** - * Searches {@link MediaItem media items} from the connected service. Not - * all services may support this, and {@link SearchCallback#onError} will be - * called if not implemented. - * - * @param query The search query that contains keywords separated by space. Should not be - * an empty string. - * @param extras The bundle of service-specific arguments to send to the media browser - * service. The contents of this bundle may affect the search result. - * @param callback The callback to receive the search result. - * @throws IllegalStateException if the browser is not connected to the media browser service. - */ - public void search(@NonNull final String query, final Bundle extras, SearchCallback callback) { - if (TextUtils.isEmpty(query)) { - throw new IllegalArgumentException("query cannot be empty."); - } - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null."); - } - if (mState != CONNECT_STATE_CONNECTED) { - throw new IllegalStateException("search() called while not connected (state=" - + getStateLabel(mState) + ")"); - } - ResultReceiver receiver = new ResultReceiver(mHandler) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode != 0 || resultData == null - || !resultData.containsKey(MediaBrowserService.KEY_SEARCH_RESULTS)) { - callback.onError(query, extras); - return; - } - Parcelable[] items = resultData.getParcelableArray( - MediaBrowserService.KEY_SEARCH_RESULTS); - List<MediaItem> results = null; - if (items != null) { - results = new ArrayList<>(); - for (Parcelable item : items) { - results.add((MediaItem) item); - } - } - callback.onSearchResult(query, extras, results); - } - }; - try { - mServiceBinder.search(query, extras, receiver, mServiceCallbacks); - } catch (RemoteException e) { - Log.i(TAG, "Remote error getting media item.", e); - mHandler.post(new Runnable() { - @Override - public void run() { - callback.onError(query, extras); - } - }); - } - } - private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) { // Check arguments. if (TextUtils.isEmpty(parentId)) { @@ -945,7 +889,7 @@ public final class MediaBrowser { * @param parentId The media id of the parent media item. * @param children The children which were loaded. * @param options The bundle of service-specific arguments sent to the media - * browse service. The contents of this bundle may affect the + * browser service. The contents of this bundle may affect the * information returned when browsing. */ public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children, @@ -1004,32 +948,6 @@ public final class MediaBrowser { } /** - * Callback for receiving the result of {@link #search}. - */ - public static abstract class SearchCallback { - /** - * Called when the {@link #search} finished successfully. - * - * @param query The search query sent for the search request to the connected service. - * @param extras The bundle of service-specific arguments sent to the connected service. - * @param items The list of media items which contains the search result. - */ - public void onSearchResult(@NonNull String query, Bundle extras, - @NonNull List<MediaItem> items) { - } - - /** - * Called when an error happens while {@link #search} or the connected service doesn't - * support {@link #search}. - * - * @param query The search query sent for the search request to the connected service. - * @param extras The bundle of service-specific arguments sent to the connected service. - */ - public void onError(@NonNull String query, Bundle extras) { - } - } - - /** * ServiceConnection to the other app. */ private class MediaServiceConnection implements ServiceConnection { diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index 4f3314c1e8ab..3affee5c0aa7 100644 --- a/media/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl @@ -45,8 +45,6 @@ interface ISession { void setQueueTitle(CharSequence title); void setExtras(in Bundle extras); void setRatingType(int type); - void setRepeatMode(int repeatMode); - void setShuffleModeEnabled(boolean enabled); // These commands relate to volume handling void setPlaybackToLocal(in AudioAttributes attributes); diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl index a146c6226171..893bd3c8cbb1 100644 --- a/media/java/android/media/session/ISessionCallback.aidl +++ b/media/java/android/media/session/ISessionCallback.aidl @@ -16,7 +16,6 @@ package android.media.session; import android.content.Intent; -import android.media.MediaDescription; import android.media.Rating; import android.net.Uri; import android.os.Bundle; @@ -47,13 +46,7 @@ oneway interface ISessionCallback { void onRewind(); void onSeekTo(long pos); void onRate(in Rating rating); - void onRepeatMode(int repeatMode); - void onShuffleMode(boolean enabled); void onCustomAction(String action, in Bundle args); - void onAddQueueItem(in MediaDescription description); - void onAddQueueItemAt(in MediaDescription description, int index); - void onRemoveQueueItem(in MediaDescription description); - void onRemoveQueueItemAt(int index); // These callbacks are for volume handling void onAdjustVolume(int direction); diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index 7b5233ac0704..249bcdc802ce 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -18,7 +18,6 @@ package android.media.session; import android.app.PendingIntent; import android.content.Intent; import android.content.pm.ParceledListSlice; -import android.media.MediaDescription; import android.media.MediaMetadata; import android.media.Rating; import android.media.session.ISessionControllerCallback; @@ -49,19 +48,6 @@ interface ISessionController { ParcelableVolumeInfo getVolumeAttributes(); void adjustVolume(int direction, int flags, String packageName); void setVolumeTo(int value, int flags, String packageName); - MediaMetadata getMetadata(); - PlaybackState getPlaybackState(); - ParceledListSlice getQueue(); - void addQueueItem(in MediaDescription description); - void addQueueItemAt(in MediaDescription description, int index); - void removeQueueItem(in MediaDescription description); - void removeQueueItemAt(int index); - - CharSequence getQueueTitle(); - Bundle getExtras(); - int getRatingType(); - int getRepeatMode(); - boolean isShuffleModeEnabled(); // These commands are for the TransportControls void prepare(); @@ -81,7 +67,11 @@ interface ISessionController { void rewind(); void seekTo(long pos); void rate(in Rating rating); - void repeatMode(int repeatMode); - void shuffleMode(boolean enabled); void sendCustomAction(String action, in Bundle args); + MediaMetadata getMetadata(); + PlaybackState getPlaybackState(); + ParceledListSlice getQueue(); + CharSequence getQueueTitle(); + Bundle getExtras(); + int getRatingType(); } diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl index 9517c088bcf3..cf3176706d7e 100644 --- a/media/java/android/media/session/ISessionControllerCallback.aidl +++ b/media/java/android/media/session/ISessionControllerCallback.aidl @@ -36,6 +36,4 @@ oneway interface ISessionControllerCallback { void onQueueTitleChanged(CharSequence title); void onExtrasChanged(in Bundle extras); void onVolumeInfoChanged(in ParcelableVolumeInfo info); - void onRepeatModeChanged(int repeatMode); - void onShuffleModeChanged(boolean shuffleMode); } diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index bab2af25dde5..622900f5c7f9 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -23,7 +23,6 @@ import android.content.Context; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.AudioManager; -import android.media.MediaDescription; import android.media.MediaMetadata; import android.media.Rating; import android.media.VolumeProvider; @@ -39,7 +38,6 @@ import android.util.Log; import android.view.KeyEvent; import java.lang.ref.WeakReference; -import java.lang.UnsupportedOperationException; import java.util.ArrayList; import java.util.List; @@ -65,9 +63,7 @@ public final class MediaController { private static final int MSG_UPDATE_QUEUE = 5; private static final int MSG_UPDATE_QUEUE_TITLE = 6; private static final int MSG_UPDATE_EXTRAS = 7; - private static final int MSG_UPDATE_REPEAT_MODE = 8; - private static final int MSG_UPDATE_SHUFFLE_MODE = 9; - private static final int MSG_DESTROYED = 10; + private static final int MSG_DESTROYED = 8; private final ISessionController mSessionBinder; @@ -113,7 +109,8 @@ public final class MediaController { } /** - * Get a {@link TransportControls} instance to send transport actions to this session. + * Get a {@link TransportControls} instance to send transport actions to + * the associated session. * * @return A transport controls instance. */ @@ -152,7 +149,7 @@ public final class MediaController { try { return mSessionBinder.getPlaybackState(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getPlaybackState", e); + Log.wtf(TAG, "Error calling getPlaybackState.", e); return null; } } @@ -166,7 +163,7 @@ public final class MediaController { try { return mSessionBinder.getMetadata(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getMetadata", e); + Log.wtf(TAG, "Error calling getMetadata.", e); return null; } } @@ -184,103 +181,12 @@ public final class MediaController { return queue.getList(); } } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getQueue", e); + Log.wtf(TAG, "Error calling getQueue.", e); } return null; } /** - * Add a queue item from the given {@code description} at the end of the play queue - * of this session. Not all sessions may support this. - * - * @param description The {@link MediaDescription} for creating the - * {@link MediaSession.QueueItem} to be inserted. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void addQueueItem(MediaDescription description) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.addQueueItem(description); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling addQueueItem", e); - } - } - - /** - * Add a queue item from the given {@code description} at the specified position - * in the play queue of this session. Shifts the queue item currently at that position - * (if any) and any subsequent queue items to the right (adds one to their indices). - * Not all sessions may support this. - * - * @param description The {@link MediaDescription} for creating the - * {@link MediaSession.QueueItem} to be inserted. - * @param index The index at which the created {@link MediaSession.QueueItem} is to be inserted. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void addQueueItem(MediaDescription description, int index) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.addQueueItemAt(description, index); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling addQueueItemAt", e); - } - } - - /** - * Remove the first occurrence of the specified {@link MediaSession.QueueItem} - * with the given {@link MediaDescription description} in the play queue of the associated - * session. Not all sessions may support this. - * - * @param description The {@link MediaDescription} for denoting the - * {@link MediaSession.QueueItem} to be removed. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void removeQueueItem(MediaDescription description) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.removeQueueItem(description); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling removeQueueItem", e); - } - } - - /** - * Remove an queue item at the specified position in the play queue - * of this session. Not all sessions may support this. - * - * @param index The index of the element to be removed. - * @throws UnsupportedOperationException If this session doesn't support this. - * @see MediaSession#FLAG_HANDLES_QUEUE_COMMANDS - */ - public void removeQueueItemAt(int index) { - try { - long flags = mSessionBinder.getFlags(); - if ((flags & MediaSession.FLAG_HANDLES_QUEUE_COMMANDS) == 0) { - throw new UnsupportedOperationException( - "This session doesn't support queue management operations"); - } - mSessionBinder.removeQueueItemAt(index); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling removeQueueItemAt", e); - } - } - - /** * Get the queue title for this session. */ public @Nullable CharSequence getQueueTitle() { @@ -322,41 +228,12 @@ public final class MediaController { try { return mSessionBinder.getRatingType(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getRatingType", e); + Log.wtf(TAG, "Error calling getRatingType.", e); return Rating.RATING_NONE; } } /** - * Get the repeat mode for this session. - * - * @return The latest repeat mode set to the session, or - * {@link PlaybackState#REPEAT_MODE_NONE} if not set. - */ - public int getRepeatMode() { - try { - return mSessionBinder.getRepeatMode(); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getRepeatMode", e); - return PlaybackState.REPEAT_MODE_NONE; - } - } - - /** - * Return whether the shuffle mode is enabled for this session. - * - * @return {@code true} if the shuffle mode is enabled, {@code false} if disabled or not set. - */ - public boolean isShuffleModeEnabled() { - try { - return mSessionBinder.isShuffleModeEnabled(); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling isShuffleModeEnabled", e); - return false; - } - } - - /** * Get the flags for this session. Flags are defined in {@link MediaSession}. * * @return The current set of flags for the session. @@ -365,7 +242,7 @@ public final class MediaController { try { return mSessionBinder.getFlags(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getFlags", e); + Log.wtf(TAG, "Error calling getFlags.", e); } return 0; } @@ -382,7 +259,7 @@ public final class MediaController { result.maxVolume, result.currentVolume); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getAudioInfo", e); + Log.wtf(TAG, "Error calling getAudioInfo.", e); } return null; } @@ -397,7 +274,7 @@ public final class MediaController { try { return mSessionBinder.getLaunchPendingIntent(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling getPendingIntent", e); + Log.wtf(TAG, "Error calling getPendingIntent.", e); } return null; } @@ -426,7 +303,7 @@ public final class MediaController { try { mSessionBinder.setVolumeTo(value, flags, mContext.getPackageName()); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling setVolumeTo", e); + Log.wtf(TAG, "Error calling setVolumeTo.", e); } } @@ -447,7 +324,7 @@ public final class MediaController { try { mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName()); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling adjustVolumeBy", e); + Log.wtf(TAG, "Error calling adjustVolumeBy.", e); } } @@ -513,7 +390,7 @@ public final class MediaController { try { mSessionBinder.sendCommand(command, args, cb); } catch (RemoteException e) { - Log.d(TAG, "Dead object in sendCommand", e); + Log.d(TAG, "Dead object in sendCommand.", e); } } @@ -527,7 +404,7 @@ public final class MediaController { try { mPackageName = mSessionBinder.getPackageName(); } catch (RemoteException e) { - Log.d(TAG, "Dead object in getPackageName", e); + Log.d(TAG, "Dead object in getPackageName.", e); } } return mPackageName; @@ -544,7 +421,7 @@ public final class MediaController { try { mTag = mSessionBinder.getTag(); } catch (RemoteException e) { - Log.d(TAG, "Dead object in getTag", e); + Log.d(TAG, "Dead object in getTag.", e); } } return mTag; @@ -702,25 +579,6 @@ public final class MediaController { */ public void onAudioInfoChanged(PlaybackInfo info) { } - - /** - * Override to handle changes to the repeat mode. - * - * @param repeatMode The repeat mode. It should be one of followings: - * {@link PlaybackState#REPEAT_MODE_NONE}, - * {@link PlaybackState#REPEAT_MODE_ONE}, - * {@link PlaybackState#REPEAT_MODE_ALL} - */ - public void onRepeatModeChanged(@PlaybackState.RepeatMode int repeatMode) { - } - - /** - * Override to handle changes to the shuffle mode. - * - * @param enabled {@code true} if the shuffle mode is enabled, {@code false} otherwise. - */ - public void onShuffleModeChanged(boolean enabled) { - } } /** @@ -744,7 +602,7 @@ public final class MediaController { try { mSessionBinder.prepare(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare", e); + Log.wtf(TAG, "Error calling prepare.", e); } } @@ -763,12 +621,12 @@ public final class MediaController { public void prepareFromMediaId(String mediaId, Bundle extras) { if (TextUtils.isEmpty(mediaId)) { throw new IllegalArgumentException( - "You must specify a non-empty String for prepareFromMediaId"); + "You must specify a non-empty String for prepareFromMediaId."); } try { mSessionBinder.prepareFromMediaId(mediaId, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare(" + mediaId + ")", e); + Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e); } } @@ -794,7 +652,7 @@ public final class MediaController { try { mSessionBinder.prepareFromSearch(query, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare(" + query + ")", e); + Log.wtf(TAG, "Error calling prepare(" + query + ").", e); } } @@ -813,12 +671,12 @@ public final class MediaController { public void prepareFromUri(Uri uri, Bundle extras) { if (uri == null || Uri.EMPTY.equals(uri)) { throw new IllegalArgumentException( - "You must specify a non-empty Uri for prepareFromUri"); + "You must specify a non-empty Uri for prepareFromUri."); } try { mSessionBinder.prepareFromUri(uri, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling prepare(" + uri + ")", e); + Log.wtf(TAG, "Error calling prepare(" + uri + ").", e); } } @@ -829,7 +687,7 @@ public final class MediaController { try { mSessionBinder.play(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play", e); + Log.wtf(TAG, "Error calling play.", e); } } @@ -843,12 +701,12 @@ public final class MediaController { public void playFromMediaId(String mediaId, Bundle extras) { if (TextUtils.isEmpty(mediaId)) { throw new IllegalArgumentException( - "You must specify a non-empty String for playFromMediaId"); + "You must specify a non-empty String for playFromMediaId."); } try { mSessionBinder.playFromMediaId(mediaId, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play(" + mediaId + ")", e); + Log.wtf(TAG, "Error calling play(" + mediaId + ").", e); } } @@ -870,7 +728,7 @@ public final class MediaController { try { mSessionBinder.playFromSearch(query, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play(" + query + ")", e); + Log.wtf(TAG, "Error calling play(" + query + ").", e); } } @@ -884,12 +742,12 @@ public final class MediaController { public void playFromUri(Uri uri, Bundle extras) { if (uri == null || Uri.EMPTY.equals(uri)) { throw new IllegalArgumentException( - "You must specify a non-empty Uri for playFromUri"); + "You must specify a non-empty Uri for playFromUri."); } try { mSessionBinder.playFromUri(uri, extras); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling play(" + uri + ")", e); + Log.wtf(TAG, "Error calling play(" + uri + ").", e); } } @@ -901,7 +759,7 @@ public final class MediaController { try { mSessionBinder.skipToQueueItem(id); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling skipToItem(" + id + ")", e); + Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e); } } @@ -913,7 +771,7 @@ public final class MediaController { try { mSessionBinder.pause(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling pause", e); + Log.wtf(TAG, "Error calling pause.", e); } } @@ -925,7 +783,7 @@ public final class MediaController { try { mSessionBinder.stop(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling stop", e); + Log.wtf(TAG, "Error calling stop.", e); } } @@ -938,7 +796,7 @@ public final class MediaController { try { mSessionBinder.seekTo(pos); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling seekTo", e); + Log.wtf(TAG, "Error calling seekTo.", e); } } @@ -950,7 +808,7 @@ public final class MediaController { try { mSessionBinder.fastForward(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling fastForward", e); + Log.wtf(TAG, "Error calling fastForward.", e); } } @@ -961,7 +819,7 @@ public final class MediaController { try { mSessionBinder.next(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling next", e); + Log.wtf(TAG, "Error calling next.", e); } } @@ -973,7 +831,7 @@ public final class MediaController { try { mSessionBinder.rewind(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling rewind", e); + Log.wtf(TAG, "Error calling rewind.", e); } } @@ -984,7 +842,7 @@ public final class MediaController { try { mSessionBinder.previous(); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling previous", e); + Log.wtf(TAG, "Error calling previous.", e); } } @@ -999,36 +857,7 @@ public final class MediaController { try { mSessionBinder.rate(rating); } catch (RemoteException e) { - Log.wtf(TAG, "Error calling rate", e); - } - } - - /** - * Set the repeat mode for this session. - * - * @param repeatMode The repeat mode. Must be one of the followings: - * {@link PlaybackState#REPEAT_MODE_NONE}, - * {@link PlaybackState#REPEAT_MODE_ONE}, - * {@link PlaybackState#REPEAT_MODE_ALL} - */ - public void setRepeatMode(@PlaybackState.RepeatMode int repeatMode) { - try { - mSessionBinder.repeatMode(repeatMode); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling setRepeatMode", e); - } - } - - /** - * Set the shuffle mode for this session. - * - * @param enabled {@code true} to enable the shuffle mode, {@code false} to disable. - */ - public void setShuffleModeEnabled(boolean enabled) { - try { - mSessionBinder.shuffleMode(enabled); - } catch (RemoteException e) { - Log.wtf(TAG, "Error calling shuffleMode", e); + Log.wtf(TAG, "Error calling rate.", e); } } @@ -1042,7 +871,7 @@ public final class MediaController { public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, @Nullable Bundle args) { if (customAction == null) { - throw new IllegalArgumentException("CustomAction cannot be null"); + throw new IllegalArgumentException("CustomAction cannot be null."); } sendCustomAction(customAction.getAction(), args); } @@ -1058,12 +887,12 @@ public final class MediaController { */ public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { if (TextUtils.isEmpty(action)) { - throw new IllegalArgumentException("CustomAction cannot be null"); + throw new IllegalArgumentException("CustomAction cannot be null."); } try { mSessionBinder.sendCustomAction(action, args); } catch (RemoteException e) { - Log.d(TAG, "Dead object in sendCustomAction", e); + Log.d(TAG, "Dead object in sendCustomAction.", e); } } } @@ -1233,21 +1062,6 @@ public final class MediaController { } } - @Override - public void onRepeatModeChanged(int repeatMode) { - MediaController controller = mController.get(); - if (controller != null) { - controller.postMessage(MSG_UPDATE_REPEAT_MODE, repeatMode, null); - } - } - - @Override - public void onShuffleModeChanged(boolean enabled) { - MediaController controller = mController.get(); - if (controller != null) { - controller.postMessage(MSG_UPDATE_SHUFFLE_MODE, enabled, null); - } - } } private final static class MessageHandler extends Handler { @@ -1286,12 +1100,6 @@ public final class MediaController { case MSG_UPDATE_VOLUME: mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj); break; - case MSG_UPDATE_REPEAT_MODE: - mCallback.onRepeatModeChanged((int) msg.obj); - break; - case MSG_UPDATE_SHUFFLE_MODE: - mCallback.onShuffleModeChanged((boolean) msg.obj); - break; case MSG_DESTROYED: mCallback.onSessionDestroyed(); break; diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index f10f4427d6f0..dfd2bb35d6ea 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -93,12 +93,6 @@ public final class MediaSession { public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1; /** - * Set this flag on the session to indicate that it handles queue - * management commands through its {@link Callback}. - */ - public static final int FLAG_HANDLES_QUEUE_COMMANDS = 1 << 2; - - /** * System only flag for a session that needs to have priority over all other * sessions. This flag ensures this session will receive media button events * regardless of the current ordering in the system. @@ -112,7 +106,6 @@ public final class MediaSession { @IntDef(flag = true, value = { FLAG_HANDLES_MEDIA_BUTTONS, FLAG_HANDLES_TRANSPORT_CONTROLS, - FLAG_HANDLES_QUEUE_COMMANDS, FLAG_EXCLUSIVE_GLOBAL_PRIORITY }) public @interface SessionFlags { } @@ -493,41 +486,6 @@ public final class MediaSession { } /** - * Set the repeat mode for this session. - * <p> - * Note that if this method is not called before, {@link MediaController#getRepeatMode} - * will return {@link PlaybackState#REPEAT_MODE_NONE}. - * - * @param repeatMode The repeat mode. Must be one of the followings: - * {@link PlaybackState#REPEAT_MODE_NONE}, - * {@link PlaybackState#REPEAT_MODE_ONE}, - * {@link PlaybackState#REPEAT_MODE_ALL} - */ - public void setRepeatMode(@PlaybackState.RepeatMode int repeatMode) { - try { - mBinder.setRepeatMode(repeatMode); - } catch (RemoteException e) { - Log.e(TAG, "Error in setRepeatMode.", e); - } - } - - /** - * Set the shuffle mode for this session. - * <p> - * Note that if this method is not called before, {@link MediaController#isShuffleModeEnabled} - * will return {@code false}. - * - * @param enabled {@code true} to enable the shuffle mode, {@code false} to disable. - */ - public void setShuffleModeEnabled(boolean enabled) { - try { - mBinder.setShuffleModeEnabled(enabled); - } catch (RemoteException e) { - Log.e(TAG, "Error in setShuffleModeEnabled.", e); - } - } - - /** * Set some extras that can be associated with the {@link MediaSession}. No assumptions should * be made as to how a {@link MediaController} will handle these extras. * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts. @@ -646,34 +604,10 @@ public final class MediaSession { postToCallback(CallbackMessageHandler.MSG_RATE, rating); } - private void dispatchRepeatMode(int repeatMode) { - postToCallback(CallbackMessageHandler.MSG_REPEAT_MODE, repeatMode); - } - - private void dispatchShuffleMode(boolean enabled) { - postToCallback(CallbackMessageHandler.MSG_SHUFFLE_MODE, enabled); - } - private void dispatchCustomAction(String action, Bundle args) { postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args); } - private void dispatchAddQueueItem(MediaDescription description) { - postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM, description); - } - - private void dispatchAddQueueItem(MediaDescription description, int index) { - postToCallback(CallbackMessageHandler.MSG_ADD_QUEUE_ITEM_AT, description, index); - } - - private void dispatchRemoveQueueItem(MediaDescription description) { - postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM, description); - } - - private void dispatchRemoveQueueItemAt(int index) { - postToCallback(CallbackMessageHandler.MSG_REMOVE_QUEUE_ITEM_AT, index); - } - private void dispatchMediaButton(Intent mediaButtonIntent) { postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent); } @@ -695,22 +629,10 @@ public final class MediaSession { postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd); } - private void postToCallback(int what, int arg1) { - postToCallback(what, null, arg1); - } - private void postToCallback(int what, Object obj) { postToCallback(what, obj, null); } - private void postToCallback(int what, Object obj, int arg1) { - synchronized (mLock) { - if (mCallback != null) { - mCallback.post(what, obj, arg1); - } - } - } - private void postToCallback(int what, Object obj, Bundle extras) { synchronized (mLock) { if (mCallback != null) { @@ -1048,33 +970,6 @@ public final class MediaSession { } /** - * Override to handle the setting of the repeat mode. - * <p> - * You should call {@link #setRepeatMode} before end of this method in order to notify - * the change to the {@link MediaController}, or {@link MediaController#getRepeatMode} - * could return an invalid value. - * - * @param repeatMode The repeat mode which is one of followings: - * {@link PlaybackState#REPEAT_MODE_NONE}, - * {@link PlaybackState#REPEAT_MODE_ONE}, - * {@link PlaybackState#REPEAT_MODE_ALL} - */ - public void onSetRepeatMode(@PlaybackState.RepeatMode int repeatMode) { - } - - /** - * Override to handle the setting of the shuffle mode. - * <p> - * You should call {@link #setShuffleModeEnabled} before the end of this method in order to - * notify the change to the {@link MediaController}, or - * {@link MediaController#isShuffleModeEnabled} could return an invalid value. - * - * @param enabled true when the shuffle mode is enabled, false otherwise. - */ - public void onSetShuffleModeEnabled(boolean enabled) { - } - - /** * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be * performed. * @@ -1084,47 +979,6 @@ public final class MediaSession { */ public void onCustomAction(@NonNull String action, @Nullable Bundle extras) { } - - /** - * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given - * {@link MediaDescription description} at the end of the play queue. - * - * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be - * inserted. - */ - public void onAddQueueItem(MediaDescription description) { - } - - /** - * Called when a {@link MediaController} wants to add a {@link QueueItem} with the given - * {@link MediaDescription description} at the specified position in the play queue. - * - * @param description The {@link MediaDescription} for creating the {@link QueueItem} to be - * inserted. - * @param index The index at which the created {@link QueueItem} is to be inserted. - */ - public void onAddQueueItem(MediaDescription description, int index) { - } - - /** - * Called when a {@link MediaController} wants to remove the first occurrence of the - * specified {@link QueueItem} with the given {@link MediaDescription description} - * in the play queue. - * - * @param description The {@link MediaDescription} for denoting the {@link QueueItem} to be - * removed. - */ - public void onRemoveQueueItem(MediaDescription description) { - } - - /** - * Called when a {@link MediaController} wants to remove a {@link QueueItem} at the - * specified position in the play queue. - * - * @param index The index of the element to be removed. - */ - public void onRemoveQueueItemAt(int index) { - } } /** @@ -1297,22 +1151,6 @@ public final class MediaSession { } @Override - public void onRepeatMode(int repeatMode) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchRepeatMode(repeatMode); - } - } - - @Override - public void onShuffleMode(boolean enabled) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchShuffleMode(enabled); - } - } - - @Override public void onCustomAction(String action, Bundle args) { MediaSession session = mMediaSession.get(); if (session != null) { @@ -1321,38 +1159,6 @@ public final class MediaSession { } @Override - public void onAddQueueItem(MediaDescription description) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchAddQueueItem(description); - } - } - - @Override - public void onAddQueueItemAt(MediaDescription description, int index) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchAddQueueItem(description, index); - } - } - - @Override - public void onRemoveQueueItem(MediaDescription description) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchRemoveQueueItem(description); - } - } - - @Override - public void onRemoveQueueItemAt(int index) { - MediaSession session = mMediaSession.get(); - if (session != null) { - session.dispatchRemoveQueueItemAt(index); - } - } - - @Override public void onAdjustVolume(int direction) { MediaSession session = mMediaSession.get(); if (session != null) { @@ -1376,7 +1182,7 @@ public final class MediaSession { */ public static final class QueueItem implements Parcelable { /** - * This id is reserved. No items can be explicitly asigned this id. + * This id is reserved. No items can be explicitly assigned this id. */ public static final int UNKNOWN_ID = -1; @@ -1485,15 +1291,9 @@ public final class MediaSession { private static final int MSG_REWIND = 17; private static final int MSG_SEEK_TO = 18; private static final int MSG_RATE = 19; - private static final int MSG_REPEAT_MODE = 20; - private static final int MSG_SHUFFLE_MODE = 21; - private static final int MSG_CUSTOM_ACTION = 22; - private static final int MSG_ADJUST_VOLUME = 23; - private static final int MSG_SET_VOLUME = 24; - private static final int MSG_ADD_QUEUE_ITEM = 25; - private static final int MSG_ADD_QUEUE_ITEM_AT = 26; - private static final int MSG_REMOVE_QUEUE_ITEM = 27; - private static final int MSG_REMOVE_QUEUE_ITEM_AT = 28; + private static final int MSG_CUSTOM_ACTION = 20; + private static final int MSG_ADJUST_VOLUME = 21; + private static final int MSG_SET_VOLUME = 22; private MediaSession.Callback mCallback; @@ -1582,33 +1382,15 @@ public final class MediaSession { case MSG_RATE: mCallback.onSetRating((Rating) msg.obj); break; - case MSG_REPEAT_MODE: - mCallback.onSetRepeatMode(msg.arg1); - break; - case MSG_SHUFFLE_MODE: - mCallback.onSetShuffleModeEnabled((boolean) msg.obj); - break; case MSG_CUSTOM_ACTION: mCallback.onCustomAction((String) msg.obj, msg.getData()); break; - case MSG_ADD_QUEUE_ITEM: - mCallback.onAddQueueItem((MediaDescription) msg.obj); - break; - case MSG_ADD_QUEUE_ITEM_AT: - mCallback.onAddQueueItem((MediaDescription) msg.obj, msg.arg1); - break; - case MSG_REMOVE_QUEUE_ITEM: - mCallback.onRemoveQueueItem((MediaDescription) msg.obj); - break; - case MSG_REMOVE_QUEUE_ITEM_AT: - mCallback.onRemoveQueueItemAt(msg.arg1); - break; case MSG_ADJUST_VOLUME: synchronized (mLock) { vp = mVolumeProvider; } if (vp != null) { - vp.onAdjustVolume(msg.arg1); + vp.onAdjustVolume((int) msg.obj); } break; case MSG_SET_VOLUME: @@ -1616,7 +1398,7 @@ public final class MediaSession { vp = mVolumeProvider; } if (vp != null) { - vp.onSetVolumeTo(msg.arg1); + vp.onSetVolumeTo((int) msg.obj); } break; } diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java index 1ea61093d869..8283c8b967e8 100644 --- a/media/java/android/media/session/PlaybackState.java +++ b/media/java/android/media/session/PlaybackState.java @@ -45,8 +45,7 @@ public final class PlaybackState implements Parcelable { ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING, ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH, ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE, - ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI, - ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE_ENABLED}) + ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI}) @Retention(RetentionPolicy.SOURCE) public @interface Actions {} @@ -177,20 +176,6 @@ public final class PlaybackState implements Parcelable { public static final long ACTION_PREPARE_FROM_URI = 1 << 17; /** - * Indicates this session supports the set repeat mode command. - * - * @see Builder#setActions(long) - */ - public static final long ACTION_SET_REPEAT_MODE = 1 << 18; - - /** - * Indicates this session supports the set shuffle mode enabled command. - * - * @see Builder#setActions(long) - */ - public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 1 << 19; - - /** * @hide */ @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING, @@ -296,30 +281,6 @@ public final class PlaybackState implements Parcelable { */ public final static long PLAYBACK_POSITION_UNKNOWN = -1; - /** - * @hide - */ - @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL}) - @Retention(RetentionPolicy.SOURCE) - public @interface RepeatMode {} - /** - * Use this value with {@link MediaController.TransportControls#setRepeatMode} - * to indicate that the playback will be stopped at the end of the playing media list. - */ - public final static int REPEAT_MODE_NONE = 0; - - /** - * Use this value with {@link MediaController.TransportControls#setRepeatMode} - * to indicate that the playback of the current playing media item will be repeated. - */ - public final static int REPEAT_MODE_ONE = 1; - - /** - * Use this value with {@link MediaController.TransportControls#setRepeatMode} - * to indicate that the playback of the playing media list will be repeated. - */ - public final static int REPEAT_MODE_ALL = 2; - private final int mState; private final long mPosition; private final long mBufferedPosition; @@ -466,8 +427,6 @@ public final class PlaybackState implements Parcelable { * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li> * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li> * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li> - * <li> {@link PlaybackState#ACTION_SET_REPEAT_MODE}</li> - * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE_ENABLED}</li> * </ul> */ @Actions @@ -1002,8 +961,6 @@ public final class PlaybackState implements Parcelable { * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li> * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li> * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li> - * <li> {@link PlaybackState#ACTION_SET_REPEAT_MODE}</li> - * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE_ENABLED}</li> * </ul> * * @param actions The set of actions allowed. diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 1b55380ed5a9..71f9ba257aa3 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -436,6 +436,14 @@ public final class TvContract { public static final String PARAM_CANONICAL_GENRE = "canonical_genre"; /** + * A query, update or delete URI parameter that allows the caller to operate only on preview or + * non-preview channels. If set to "true", the operation affects the rows for preview channels + * only. If set to "false", the operation affects the rows for non-preview channels only. + * @hide + */ + public static final String PARAM_PREVIEW = "preview"; + + /** * Builds an ID that uniquely identifies a TV input service. * * @param name The {@link ComponentName} of the TV input service to build ID for. diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl index e95154ff4540..84f41f6c3afe 100644 --- a/media/java/android/service/media/IMediaBrowserService.aidl +++ b/media/java/android/service/media/IMediaBrowserService.aidl @@ -19,10 +19,8 @@ oneway interface IMediaBrowserService { void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks); void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks); - void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks); - void search(String query, in Bundle extras, in ResultReceiver cb, - IMediaBrowserServiceCallbacks callbacks); + void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks); void addSubscription(String uri, in IBinder token, in Bundle options, IMediaBrowserServiceCallbacks callbacks); void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks); diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index d372efbea5ca..b52906ddd1ae 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -89,15 +89,8 @@ public abstract class MediaBrowserService extends Service { */ public static final String KEY_MEDIA_ITEM = "media_item"; - /** - * A key for passing the list of MediaItems to the ResultReceiver in search. - * @hide - */ - public static final String KEY_SEARCH_RESULTS = "search_results"; - private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0; private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1; - private static final int RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED = 1 << 2; private static final int RESULT_ERROR = -1; private static final int RESULT_OK = 0; @@ -105,7 +98,7 @@ public abstract class MediaBrowserService extends Service { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED, - RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED, RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED }) + RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED }) private @interface ResultFlags { } private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>(); @@ -137,7 +130,6 @@ public abstract class MediaBrowserService extends Service { * * @see #onLoadChildren * @see #onLoadItem - * @see #onSearch */ public class Result<T> { private Object mDebug; @@ -330,23 +322,6 @@ public abstract class MediaBrowserService extends Service { } }); } - - @Override - public void search(final String query, Bundle extras, ResultReceiver receiver, - final IMediaBrowserServiceCallbacks callbacks) { - mHandler.post(new Runnable() { - @Override - public void run() { - final IBinder b = callbacks.asBinder(); - ConnectionRecord connection = mConnections.get(b); - if (connection == null) { - Log.w(TAG, "search for callback that isn't registered query=" + query); - return; - } - performSearch(query, extras, connection, receiver); - } - }); - } } @Override @@ -472,32 +447,6 @@ public abstract class MediaBrowserService extends Service { } /** - * Called to get the search result. - * <p> - * Implementations must call {@link Result#sendResult result.sendResult}. If - * the search will be an expensive operation {@link Result#detach result.detach} - * may be called before returning from this function, and then {@link Result#sendResult - * result.sendResult} called when the search has been completed. - * </p><p> - * In case there are no search results, call {@link Result#sendResult} with an empty list. - * In case there are some errors happened, call {@link Result#sendResult result.sendResult} - * with {@code null}, which will invoke {@link MediaBrowser.SearchCallback#onError}. - * </p><p> - * The default implementation will invoke {@link MediaBrowser.SearchCallback#onError}. - * </p> - * - * @param query The search query sent from the media browser. It contains keywords separated - * by space. - * @param extras The bundle of service-specific arguments sent from the media browser. - * @param result The {@link Result} to send the search result. - */ - public void onSearch(@NonNull String query, Bundle extras, - Result<List<MediaBrowser.MediaItem>> result) { - result.setFlags(RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED); - result.sendResult(null); - } - - /** * Call to set the media session. * <p> * This should be called as soon as possible during the service's startup. @@ -545,16 +494,16 @@ public abstract class MediaBrowserService extends Service { * media browser service when connecting and retrieving the root id for browsing, or null if * none. The contents of this bundle may affect the information returned when browsing. * - * @throws IllegalStateException If this method is called outside of {@link #onLoadChildren}, - * {@link #onLoadItem} or {@link #onSearch}. + * @throws IllegalStateException If this method is called outside of {@link #onLoadChildren} or + * {@link #onLoadItem}. * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED */ public final Bundle getBrowserRootHints() { if (mCurConnection == null) { - throw new IllegalStateException("This should be called inside of onLoadChildren," - + " onLoadItem or onSearch methods"); + throw new IllegalStateException("This should be called inside of onLoadChildren or" + + " onLoadItem methods"); } return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints); } @@ -771,34 +720,6 @@ public abstract class MediaBrowserService extends Service { } } - private void performSearch(String query, Bundle extras, final ConnectionRecord connection, - final ResultReceiver receiver) { - final Result<List<MediaBrowser.MediaItem>> result = - new Result<List<MediaBrowser.MediaItem>>(query) { - @Override - void onResultSent(List<MediaBrowser.MediaItem> items, @ResultFlags int flag) { - if ((flag & RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED) != 0 - || items == null) { - receiver.send(RESULT_ERROR, null); - return; - } - Bundle bundle = new Bundle(); - bundle.putParcelableArray(KEY_SEARCH_RESULTS, - items.toArray(new MediaBrowser.MediaItem[0])); - receiver.send(RESULT_OK, bundle); - } - }; - - mCurConnection = connection; - onSearch(query, extras, result); - mCurConnection = null; - - if (!result.isDone()) { - throw new IllegalStateException("onSearch must call detach() or sendResult()" - + " before returning for query=" + query); - } - } - /** * Contains information that the browser service needs to send to the client * when first connected. 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/native/android/sensor.cpp b/native/android/sensor.cpp index ae16949791bc..8e5821024cee 100644 --- a/native/android/sensor.cpp +++ b/native/android/sensor.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "sensor" #include <utils/Log.h> -#include <android/hardware_buffer.h> #include <android/looper.h> #include <android/sensor.h> #include <android/sharedmem.h> @@ -28,6 +27,7 @@ #include <utils/Looper.h> #include <utils/RefBase.h> #include <utils/Timers.h> +#include <vndk/hardware_buffer.h> #include <poll.h> 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/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml index e9c175f6fed0..55c192d56a4d 100644 --- a/packages/SettingsLib/res/layout/settings_with_drawer.xml +++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml @@ -25,17 +25,13 @@ android:layout_height="match_parent" android:orientation="vertical" android:fitsSystemWindows="true"> - <FrameLayout + <Toolbar + android:id="@+id/action_bar" style="?android:attr/actionBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:theme="?android:attr/actionBarTheme"> - <Toolbar - android:id="@+id/action_bar" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:navigationContentDescription="@*android:string/action_bar_up_description"/> - </FrameLayout> + android:theme="?android:attr/actionBarTheme" + android:navigationContentDescription="@*android:string/action_bar_up_description"/> <FrameLayout android:id="@+id/content_header_container" style="?android:attr/actionBarStyle" diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityButtonHelper.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityButtonHelper.java new file mode 100644 index 000000000000..972ea347e6dd --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityButtonHelper.java @@ -0,0 +1,62 @@ +/* + * 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.settingslib.accessibility; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.Context; +import android.content.res.Resources; +import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; + +import java.util.List; + +/** + * A helper class to assist determining the state of the accessibility button that can appear + * within the software-rendered navigation area. + */ +public class AccessibilityButtonHelper { + public static boolean isRequestedByMagnification(Context ctx) { + return Settings.Secure.getInt(ctx.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1; + } + + public static boolean isRequestedByAccessibilityService(Context ctx) { + final AccessibilityManager accessibilityManager = ctx.getSystemService( + AccessibilityManager.class); + List<AccessibilityServiceInfo> services = + accessibilityManager.getEnabledAccessibilityServiceList( + AccessibilityServiceInfo.FEEDBACK_ALL_MASK); + if (services != null) { + for (int i = 0, size = services.size(); i < size; i++) { + if ((services.get(i).flags + & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) + != 0) { + return true; + } + } + } + return false; + } + + public static boolean isRequested(Context ctx) { + return isRequestedByMagnification(ctx) || isRequestedByAccessibilityService(ctx); + } + + public static boolean isDeviceSupported(Resources res) { + return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 8a86c13abb7d..10f3b6341e42 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -29,6 +29,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageStats; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; @@ -52,6 +53,7 @@ import com.android.internal.util.ArrayUtils; import com.android.settingslib.R; import java.io.File; +import java.io.IOException; import java.text.Collator; import java.text.Normalizer; import java.text.Normalizer.Form; @@ -61,6 +63,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.regex.Pattern; /** @@ -114,7 +117,7 @@ public class ApplicationsState { final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>(); List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>(); long mCurId = 1; - String mCurComputingSizeUuid; + UUID mCurComputingSizeUuid; String mCurComputingSizePkg; int mCurComputingSizeUserId; boolean mSessionsChanged; @@ -334,15 +337,23 @@ public class ApplicationsState { AppEntry entry = mEntriesMap.get(userId).get(packageName); if (entry != null && (entry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { mBackgroundHandler.post(() -> { - final StorageStats stats = mStats.queryStatsForPackage(entry.info.volumeUuid, - packageName, UserHandle.of(userId)); - final PackageStats legacyStats = new PackageStats(packageName, userId); - legacyStats.codeSize = stats.getCodeBytes(); - legacyStats.dataSize = stats.getDataBytes(); - legacyStats.cacheSize = stats.getCacheBytes(); try { - mBackgroundHandler.mStatsObserver.onGetStatsCompleted(legacyStats, true); - } catch (RemoteException ignored) { + final StorageStats stats = mStats.queryStatsForPackage( + entry.info.storageUuid, packageName, UserHandle.of(userId)); + final PackageStats legacy = new PackageStats(packageName, userId); + legacy.codeSize = stats.getCodeBytes(); + legacy.dataSize = stats.getDataBytes(); + legacy.cacheSize = stats.getCacheBytes(); + try { + mBackgroundHandler.mStatsObserver.onGetStatsCompleted(legacy, true); + } catch (RemoteException ignored) { + } + } catch (NameNotFoundException | IOException e) { + Log.w(TAG, "Failed to query stats: " + e); + try { + mBackgroundHandler.mStatsObserver.onGetStatsCompleted(null, false); + } catch (RemoteException ignored) { + } } }); } @@ -979,7 +990,7 @@ public class ApplicationsState { mMainHandler.sendMessage(m); } entry.sizeLoadStart = now; - mCurComputingSizeUuid = entry.info.volumeUuid; + mCurComputingSizeUuid = entry.info.storageUuid; mCurComputingSizePkg = entry.info.packageName; mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid); @@ -988,17 +999,17 @@ public class ApplicationsState { final StorageStats stats = mStats.queryStatsForPackage( mCurComputingSizeUuid, mCurComputingSizePkg, UserHandle.of(mCurComputingSizeUserId)); - final PackageStats legacyStats = new PackageStats( + final PackageStats legacy = new PackageStats( mCurComputingSizePkg, mCurComputingSizeUserId); - legacyStats.codeSize = stats.getCodeBytes(); - legacyStats.dataSize = stats.getDataBytes(); - legacyStats.cacheSize = stats.getCacheBytes(); + legacy.codeSize = stats.getCodeBytes(); + legacy.dataSize = stats.getDataBytes(); + legacy.cacheSize = stats.getCacheBytes(); try { - mStatsObserver.onGetStatsCompleted(legacyStats, true); + mStatsObserver.onGetStatsCompleted(legacy, true); } catch (RemoteException ignored) { } - } catch (IllegalStateException e) { - Log.e(TAG,"An exception occurred while fetching app size", e); + } catch (NameNotFoundException | IOException e) { + Log.w(TAG, "Failed to query stats: " + e); try { mStatsObserver.onGetStatsCompleted(null, false); } catch (RemoteException ignored) { diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java index 21835738fd69..34fdc9ddd99d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java @@ -19,9 +19,12 @@ package com.android.settingslib.applications; import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.os.UserHandle; import android.support.annotation.VisibleForTesting; +import java.io.IOException; + /** * StorageStatsSource wraps the StorageStatsManager for testability purposes. */ @@ -32,17 +35,21 @@ public class StorageStatsSource { mStorageStatsManager = context.getSystemService(StorageStatsManager.class); } - public StorageStatsSource.ExternalStorageStats getExternalStorageStats(String volumeUuid, UserHandle user) { + public StorageStatsSource.ExternalStorageStats getExternalStorageStats(String volumeUuid, + UserHandle user) throws IOException { return new StorageStatsSource.ExternalStorageStats( mStorageStatsManager.queryExternalStatsForUser(volumeUuid, user)); } - public StorageStatsSource.AppStorageStats getStatsForUid(String volumeUuid, int uid) { - return new StorageStatsSource.AppStorageStatsImpl(mStorageStatsManager.queryStatsForUid(volumeUuid, uid)); + public StorageStatsSource.AppStorageStats getStatsForUid(String volumeUuid, int uid) + throws IOException { + return new StorageStatsSource.AppStorageStatsImpl( + mStorageStatsManager.queryStatsForUid(volumeUuid, uid)); } public StorageStatsSource.AppStorageStats getStatsForPackage( - String volumeUuid, String packageName, UserHandle user) { + String volumeUuid, String packageName, UserHandle user) + throws PackageManager.NameNotFoundException, IOException { return new StorageStatsSource.AppStorageStatsImpl( mStorageStatsManager.queryStatsForPackage(volumeUuid, packageName, user)); } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java index 88f133ce57c2..ccf7a0bfdfc6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java @@ -20,11 +20,16 @@ import android.app.AppGlobals; import android.app.usage.StorageStatsManager; import android.content.Context; import android.os.storage.VolumeInfo; +import android.util.Log; + +import java.io.IOException; /** * PrivateStorageInfo provides information about the total and free storage on the device. */ public class PrivateStorageInfo { + private static final String TAG = "PrivateStorageInfo"; + public final long freeBytes; public final long totalBytes; @@ -41,8 +46,12 @@ public class PrivateStorageInfo { long privateTotalBytes = 0; for (VolumeInfo info : sm.getVolumes()) { if (info.getType() == VolumeInfo.TYPE_PRIVATE && info.isMountedReadable()) { - privateTotalBytes += sm.getTotalBytes(stats, info); - privateFreeBytes += sm.getFreeBytes(stats, info); + try { + privateTotalBytes += sm.getTotalBytes(stats, info); + privateFreeBytes += sm.getFreeBytes(stats, info); + } catch (IOException e) { + Log.w(TAG, e); + } } } return new PrivateStorageInfo(privateFreeBytes, privateTotalBytes); @@ -51,6 +60,11 @@ public class PrivateStorageInfo { public static long getTotalSize(VolumeInfo info, long totalInternalStorage) { final Context context = AppGlobals.getInitialApplication(); final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); - return stats.getTotalBytes(info.getFsUuid()); + try { + return stats.getTotalBytes(info.getFsUuid()); + } catch (IOException e) { + Log.w(TAG, e); + return 0; + } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java index 11060e6c1a05..b57b6cc544fa 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java @@ -20,6 +20,7 @@ import android.app.usage.StorageStatsManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import java.io.IOException; import java.util.List; /** @@ -49,12 +50,12 @@ public class StorageManagerVolumeProvider implements StorageVolumeProvider { } @Override - public long getTotalBytes(StorageStatsManager stats, VolumeInfo volume) { + public long getTotalBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException { return stats.getTotalBytes(volume.getFsUuid()); } @Override - public long getFreeBytes(StorageStatsManager stats, VolumeInfo volume) { + public long getFreeBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException { return stats.getFreeBytes(volume.getFsUuid()); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java index 60e10a125d0b..ea28fe68e91b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java @@ -32,6 +32,7 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseLongArray; +import java.io.IOException; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.List; @@ -154,7 +155,7 @@ public class StorageMeasurement { try { details.totalSize = mStats.getTotalBytes(mVolume.fsUuid); details.availSize = mStats.getFreeBytes(mVolume.fsUuid); - } catch (IllegalStateException e) { + } catch (IOException e) { // The storage volume became null while we were measuring it. Log.w(TAG, e); return details; @@ -169,8 +170,14 @@ public class StorageMeasurement { final HashMap<String, Long> mediaMap = new HashMap<>(); details.mediaSize.put(user.id, mediaMap); - final ExternalStorageStats stats = mStats - .queryExternalStatsForUser(mSharedVolume.fsUuid, UserHandle.of(user.id)); + final ExternalStorageStats stats; + try { + stats = mStats.queryExternalStatsForUser(mSharedVolume.fsUuid, + UserHandle.of(user.id)); + } catch (IOException e) { + Log.w(TAG, e); + continue; + } addValue(details.usersSize, user.id, stats.getTotalBytes()); @@ -190,8 +197,13 @@ public class StorageMeasurement { if ((mVolume.getType() == VolumeInfo.TYPE_PRIVATE) && mVolume.isMountedReadable()) { for (UserInfo user : users) { - final StorageStats stats = mStats.queryStatsForUser(mVolume.fsUuid, - UserHandle.of(user.id)); + final StorageStats stats; + try { + stats = mStats.queryStatsForUser(mVolume.fsUuid, UserHandle.of(user.id)); + } catch (IOException e) { + Log.w(TAG, e); + continue; + } // Only count code once against current user if (user.id == UserHandle.myUserId()) { diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java index e5d85d147bee..4c4541315e07 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java @@ -19,6 +19,7 @@ package com.android.settingslib.deviceinfo; import android.app.usage.StorageStatsManager; import android.os.storage.VolumeInfo; +import java.io.IOException; import java.util.List; /** @@ -46,12 +47,12 @@ public interface StorageVolumeProvider { * * @pre The volume is a private volume and is readable. */ - long getTotalBytes(StorageStatsManager stats, VolumeInfo volume); + long getTotalBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException; /** * Returns the free bytes for a given storage volume. * * @pre The volume is a private volume and is readable. */ - long getFreeBytes(StorageStatsManager stats, VolumeInfo volume); + long getFreeBytes(StorageStatsManager stats, VolumeInfo volume) throws IOException; } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java index d6bde8132327..9d09737a14dc 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java @@ -40,6 +40,8 @@ public final class CategoryKey { "com.android.settings.category.ia.language"; public static final String CATEGORY_SYSTEM_DEVELOPMENT = "com.android.settings.category.ia.development"; + public static final String CATEGORY_NOTIFICATIONS = + "com.android.settings.category.ia.notifications"; public static final Map<String, String> KEY_COMPAT_MAP; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index f277165d8f31..314791e3105a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -234,10 +234,19 @@ public class WifiTracker { } /** - * Forces an update of the wifi networks when not scanning. + * Synchronously update the list of access points with the latest information. */ public void forceUpdate() { + mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_ACCESS_POINTS); + + mLastInfo = mWifiManager.getConnectionInfo(); + mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork()); updateAccessPoints(); + + // Synchronously copy access points + mMainHandler.removeMessages(MainHandler.MSG_ACCESS_POINT_CHANGED); + mMainHandler.handleMessage( + Message.obtain(mMainHandler, MainHandler.MSG_ACCESS_POINT_CHANGED)); } /** diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java index f9e695db447c..b938fe2ac2db 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java @@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.atLeast; @@ -33,12 +32,13 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.Network; import android.net.NetworkBadging; import android.net.NetworkInfo; import android.net.NetworkKey; import android.net.NetworkScoreManager; -import android.net.ScoredNetwork; import android.net.RssiCurve; +import android.net.ScoredNetwork; import android.net.WifiKey; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; @@ -47,10 +47,10 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiNetworkScoreCache; import android.net.wifi.WifiSsid; import android.os.Bundle; -import android.os.SystemClock; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; +import android.os.SystemClock; import android.provider.Settings; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; @@ -62,8 +62,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Matchers; import org.mockito.Captor; +import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; @@ -666,4 +666,29 @@ public class WifiTrackerTest { verify(mockWifiManager, atLeast(2)).getConnectionInfo(); assertThat(tracker.getAccessPoints().get(0).getRssi()).isEqualTo(newRssi); } + + @Test + public void forceUpdateShouldSynchronouslyFetchLatestInformation() throws Exception { + when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO); + + WifiConfiguration configuration = new WifiConfiguration(); + configuration.SSID = SSID_1; + configuration.BSSID = BSSID_1; + configuration.networkId = CONNECTED_NETWORK_ID; + when(mockWifiManager.getConfiguredNetworks()).thenReturn(Arrays.asList(configuration)); + + NetworkInfo networkInfo = new NetworkInfo( + ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype"); + networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test"); + when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(networkInfo); + + + WifiTracker tracker = createMockedWifiTracker(); + startTracking(tracker); + tracker.forceUpdate(); + + verify(mockWifiListener).onAccessPointsChanged(); + assertThat(tracker.getAccessPoints().size()).isEqualTo(2); + assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue(); + } }
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_background_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_background_enter_animation.xml deleted file mode 100644 index 9ab41d0be525..000000000000 --- a/packages/SystemUI/res/anim/tv_pip_onboarding_background_enter_animation.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android"> - - <objectAnimator - android:propertyName="alpha" - android:valueFrom="0" - android:valueTo="0.9" - android:interpolator="@android:interpolator/linear" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> -</set> diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml deleted file mode 100644 index 01c263b05217..000000000000 --- a/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android"> - - <objectAnimator - android:propertyName="translationY" - android:valueFrom="114dp" - android:valueTo="0dp" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> - <objectAnimator - android:propertyName="alpha" - android:valueTo="1" - android:interpolator="@android:interpolator/linear" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> -</set> diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml deleted file mode 100644 index a12b3b680613..000000000000 --- a/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android"> - - <objectAnimator - android:propertyName="translationY" - android:valueFrom="84dp" - android:valueTo="0dp" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> - <objectAnimator - android:propertyName="alpha" - android:valueTo="1" - android:interpolator="@android:interpolator/linear" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> -</set> diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml deleted file mode 100644 index ae9677ed8a0a..000000000000 --- a/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android"> - - <objectAnimator - android:propertyName="translationY" - android:valueFrom="114dp" - android:valueTo="0dp" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> - <objectAnimator - android:propertyName="alpha" - android:valueTo="1" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> -</set> diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml deleted file mode 100644 index 4bde070dafbe..000000000000 --- a/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android"> - - <objectAnimator - android:propertyName="translationY" - android:valueFrom="84dp" - android:valueTo="0dp" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> - <objectAnimator - android:propertyName="alpha" - android:valueTo="1" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="@integer/tv_pip_onboarding_anim_duration" /> -</set> diff --git a/packages/SystemUI/res/anim/tv_pip_overlay_fade_in_animation.xml b/packages/SystemUI/res/anim/tv_pip_overlay_fade_in_animation.xml deleted file mode 100644 index 33bceaa77ce9..000000000000 --- a/packages/SystemUI/res/anim/tv_pip_overlay_fade_in_animation.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" - android:propertyName="alpha" - android:valueTo="1" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="350" /> diff --git a/packages/SystemUI/res/anim/tv_pip_overlay_fade_out_animation.xml b/packages/SystemUI/res/anim/tv_pip_overlay_fade_out_animation.xml deleted file mode 100644 index a12ddffc0bfc..000000000000 --- a/packages/SystemUI/res/anim/tv_pip_overlay_fade_out_animation.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" - android:propertyName="alpha" - android:valueTo="0" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="500" /> diff --git a/packages/SystemUI/res/color/segmented_button_text_selector.xml b/packages/SystemUI/res/color/segmented_button_text_selector.xml index 537cbb84f647..d4f01816a608 100644 --- a/packages/SystemUI/res/color/segmented_button_text_selector.xml +++ b/packages/SystemUI/res/color/segmented_button_text_selector.xml @@ -18,4 +18,4 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="?android:attr/textColorPrimary"/> <item android:alpha="0.58" android:color="?android:attr/colorForeground"/> -</selector>
\ No newline at end of file +</selector> diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_0.png b/packages/SystemUI/res/drawable-xhdpi/remote_0.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_0.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_1.png b/packages/SystemUI/res/drawable-xhdpi/remote_1.png Binary files differdeleted file mode 100644 index 252ff5ed4971..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_1.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_10.png b/packages/SystemUI/res/drawable-xhdpi/remote_10.png Binary files differdeleted file mode 100644 index 5e52b378abfe..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_10.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_100.png b/packages/SystemUI/res/drawable-xhdpi/remote_100.png Binary files differdeleted file mode 100644 index f604808357ca..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_100.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_101.png b/packages/SystemUI/res/drawable-xhdpi/remote_101.png Binary files differdeleted file mode 100644 index 0272e45267d6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_101.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_102.png b/packages/SystemUI/res/drawable-xhdpi/remote_102.png Binary files differdeleted file mode 100644 index aaa35c01bb26..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_102.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_103.png b/packages/SystemUI/res/drawable-xhdpi/remote_103.png Binary files differdeleted file mode 100644 index 20f95a582737..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_103.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_104.png b/packages/SystemUI/res/drawable-xhdpi/remote_104.png Binary files differdeleted file mode 100644 index 052f23e67d3f..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_104.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_105.png b/packages/SystemUI/res/drawable-xhdpi/remote_105.png Binary files differdeleted file mode 100644 index c5c82566d62a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_105.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_106.png b/packages/SystemUI/res/drawable-xhdpi/remote_106.png Binary files differdeleted file mode 100644 index 4e804feaf18a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_106.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_107.png b/packages/SystemUI/res/drawable-xhdpi/remote_107.png Binary files differdeleted file mode 100644 index 76669ccd2193..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_107.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_108.png b/packages/SystemUI/res/drawable-xhdpi/remote_108.png Binary files differdeleted file mode 100644 index c1b2f3bb5a1a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_108.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_109.png b/packages/SystemUI/res/drawable-xhdpi/remote_109.png Binary files differdeleted file mode 100644 index 79e1d7b221b0..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_109.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_11.png b/packages/SystemUI/res/drawable-xhdpi/remote_11.png Binary files differdeleted file mode 100644 index cfec6cbd4722..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_11.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_110.png b/packages/SystemUI/res/drawable-xhdpi/remote_110.png Binary files differdeleted file mode 100644 index d90229739200..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_110.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_111.png b/packages/SystemUI/res/drawable-xhdpi/remote_111.png Binary files differdeleted file mode 100644 index e48ed0b4c3c4..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_111.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_112.png b/packages/SystemUI/res/drawable-xhdpi/remote_112.png Binary files differdeleted file mode 100644 index 90dd1a232cb3..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_112.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_113.png b/packages/SystemUI/res/drawable-xhdpi/remote_113.png Binary files differdeleted file mode 100644 index 8fb4ad2aad87..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_113.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_114.png b/packages/SystemUI/res/drawable-xhdpi/remote_114.png Binary files differdeleted file mode 100644 index 76873fb35534..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_114.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_115.png b/packages/SystemUI/res/drawable-xhdpi/remote_115.png Binary files differdeleted file mode 100644 index e923d4c53d19..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_115.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_116.png b/packages/SystemUI/res/drawable-xhdpi/remote_116.png Binary files differdeleted file mode 100644 index 41d512488e4a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_116.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_117.png b/packages/SystemUI/res/drawable-xhdpi/remote_117.png Binary files differdeleted file mode 100644 index eacde6446953..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_117.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_118.png b/packages/SystemUI/res/drawable-xhdpi/remote_118.png Binary files differdeleted file mode 100644 index 5dc1fb035f2a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_118.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_119.png b/packages/SystemUI/res/drawable-xhdpi/remote_119.png Binary files differdeleted file mode 100644 index a16f037f1599..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_119.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_12.png b/packages/SystemUI/res/drawable-xhdpi/remote_12.png Binary files differdeleted file mode 100644 index 28bb387291e9..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_12.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_120.png b/packages/SystemUI/res/drawable-xhdpi/remote_120.png Binary files differdeleted file mode 100644 index fe3ef4176991..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_120.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_121.png b/packages/SystemUI/res/drawable-xhdpi/remote_121.png Binary files differdeleted file mode 100644 index ef2b892ffe6d..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_121.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_122.png b/packages/SystemUI/res/drawable-xhdpi/remote_122.png Binary files differdeleted file mode 100644 index 53429765345c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_122.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_123.png b/packages/SystemUI/res/drawable-xhdpi/remote_123.png Binary files differdeleted file mode 100644 index bb8a53a5aa68..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_123.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_124.png b/packages/SystemUI/res/drawable-xhdpi/remote_124.png Binary files differdeleted file mode 100644 index b68337e53e9d..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_124.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_125.png b/packages/SystemUI/res/drawable-xhdpi/remote_125.png Binary files differdeleted file mode 100644 index 81fa3a789542..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_125.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_126.png b/packages/SystemUI/res/drawable-xhdpi/remote_126.png Binary files differdeleted file mode 100644 index 2339d74f33e0..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_126.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_127.png b/packages/SystemUI/res/drawable-xhdpi/remote_127.png Binary files differdeleted file mode 100644 index 90d1e0b453df..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_127.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_128.png b/packages/SystemUI/res/drawable-xhdpi/remote_128.png Binary files differdeleted file mode 100644 index 6de4eb8cb77b..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_128.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_129.png b/packages/SystemUI/res/drawable-xhdpi/remote_129.png Binary files differdeleted file mode 100644 index 908607425ff8..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_129.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_13.png b/packages/SystemUI/res/drawable-xhdpi/remote_13.png Binary files differdeleted file mode 100644 index a1e212dc4f11..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_13.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_130.png b/packages/SystemUI/res/drawable-xhdpi/remote_130.png Binary files differdeleted file mode 100644 index 2bc9698cc095..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_130.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_131.png b/packages/SystemUI/res/drawable-xhdpi/remote_131.png Binary files differdeleted file mode 100644 index d18d2c672992..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_131.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_132.png b/packages/SystemUI/res/drawable-xhdpi/remote_132.png Binary files differdeleted file mode 100644 index 10a00cdd06bf..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_132.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_133.png b/packages/SystemUI/res/drawable-xhdpi/remote_133.png Binary files differdeleted file mode 100644 index 6f495b42513a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_133.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_134.png b/packages/SystemUI/res/drawable-xhdpi/remote_134.png Binary files differdeleted file mode 100644 index 703f2c634263..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_134.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_135.png b/packages/SystemUI/res/drawable-xhdpi/remote_135.png Binary files differdeleted file mode 100644 index f4105b0a38ab..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_135.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_136.png b/packages/SystemUI/res/drawable-xhdpi/remote_136.png Binary files differdeleted file mode 100644 index 0c3a5bcdc8a3..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_136.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_137.png b/packages/SystemUI/res/drawable-xhdpi/remote_137.png Binary files differdeleted file mode 100644 index cbebc05275e6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_137.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_138.png b/packages/SystemUI/res/drawable-xhdpi/remote_138.png Binary files differdeleted file mode 100644 index 6dfefb0934d7..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_138.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_139.png b/packages/SystemUI/res/drawable-xhdpi/remote_139.png Binary files differdeleted file mode 100644 index 1acfdd6fbf50..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_139.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_14.png b/packages/SystemUI/res/drawable-xhdpi/remote_14.png Binary files differdeleted file mode 100644 index a503cdf2f54e..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_14.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_140.png b/packages/SystemUI/res/drawable-xhdpi/remote_140.png Binary files differdeleted file mode 100644 index 70d27c18f0ca..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_140.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_141.png b/packages/SystemUI/res/drawable-xhdpi/remote_141.png Binary files differdeleted file mode 100644 index d523a0c2c754..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_141.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_142.png b/packages/SystemUI/res/drawable-xhdpi/remote_142.png Binary files differdeleted file mode 100644 index ed6a65d1b9e1..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_142.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_143.png b/packages/SystemUI/res/drawable-xhdpi/remote_143.png Binary files differdeleted file mode 100644 index 9b048e693d4d..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_143.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_144.png b/packages/SystemUI/res/drawable-xhdpi/remote_144.png Binary files differdeleted file mode 100644 index 9e2337d15735..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_144.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_145.png b/packages/SystemUI/res/drawable-xhdpi/remote_145.png Binary files differdeleted file mode 100644 index 3f30629c6715..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_145.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_146.png b/packages/SystemUI/res/drawable-xhdpi/remote_146.png Binary files differdeleted file mode 100644 index 1288039fe4fb..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_146.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_147.png b/packages/SystemUI/res/drawable-xhdpi/remote_147.png Binary files differdeleted file mode 100644 index d060539088ef..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_147.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_148.png b/packages/SystemUI/res/drawable-xhdpi/remote_148.png Binary files differdeleted file mode 100644 index 5be839d42dfe..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_148.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_149.png b/packages/SystemUI/res/drawable-xhdpi/remote_149.png Binary files differdeleted file mode 100644 index 39d31bad5af7..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_149.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_15.png b/packages/SystemUI/res/drawable-xhdpi/remote_15.png Binary files differdeleted file mode 100644 index 56955952ebe1..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_15.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_150.png b/packages/SystemUI/res/drawable-xhdpi/remote_150.png Binary files differdeleted file mode 100644 index ec2667c2c3d3..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_150.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_151.png b/packages/SystemUI/res/drawable-xhdpi/remote_151.png Binary files differdeleted file mode 100644 index ec2667c2c3d3..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_151.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_152.png b/packages/SystemUI/res/drawable-xhdpi/remote_152.png Binary files differdeleted file mode 100644 index a5d58c8ff7b4..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_152.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_153.png b/packages/SystemUI/res/drawable-xhdpi/remote_153.png Binary files differdeleted file mode 100644 index a5d58c8ff7b4..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_153.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_154.png b/packages/SystemUI/res/drawable-xhdpi/remote_154.png Binary files differdeleted file mode 100644 index a5d58c8ff7b4..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_154.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_155.png b/packages/SystemUI/res/drawable-xhdpi/remote_155.png Binary files differdeleted file mode 100644 index 793d41179a18..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_155.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_156.png b/packages/SystemUI/res/drawable-xhdpi/remote_156.png Binary files differdeleted file mode 100644 index 793d41179a18..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_156.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_157.png b/packages/SystemUI/res/drawable-xhdpi/remote_157.png Binary files differdeleted file mode 100644 index f9d6cdc166f3..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_157.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_158.png b/packages/SystemUI/res/drawable-xhdpi/remote_158.png Binary files differdeleted file mode 100644 index da8d5d79f1ed..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_158.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_159.png b/packages/SystemUI/res/drawable-xhdpi/remote_159.png Binary files differdeleted file mode 100644 index 1e0b097db178..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_159.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_16.png b/packages/SystemUI/res/drawable-xhdpi/remote_16.png Binary files differdeleted file mode 100644 index 4ae106cc45d6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_16.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_160.png b/packages/SystemUI/res/drawable-xhdpi/remote_160.png Binary files differdeleted file mode 100644 index 8aa68ad78783..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_160.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_161.png b/packages/SystemUI/res/drawable-xhdpi/remote_161.png Binary files differdeleted file mode 100644 index e49fdd9c71ba..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_161.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_162.png b/packages/SystemUI/res/drawable-xhdpi/remote_162.png Binary files differdeleted file mode 100644 index 69257a072b4a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_162.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_163.png b/packages/SystemUI/res/drawable-xhdpi/remote_163.png Binary files differdeleted file mode 100644 index 8f0c3d5f261e..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_163.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_164.png b/packages/SystemUI/res/drawable-xhdpi/remote_164.png Binary files differdeleted file mode 100644 index a4c3229e80a9..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_164.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_165.png b/packages/SystemUI/res/drawable-xhdpi/remote_165.png Binary files differdeleted file mode 100644 index 46fae23e534a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_165.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_166.png b/packages/SystemUI/res/drawable-xhdpi/remote_166.png Binary files differdeleted file mode 100644 index 40d5a9b76f4c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_166.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_167.png b/packages/SystemUI/res/drawable-xhdpi/remote_167.png Binary files differdeleted file mode 100644 index 6bd0380a3e9a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_167.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_168.png b/packages/SystemUI/res/drawable-xhdpi/remote_168.png Binary files differdeleted file mode 100644 index 03904bf47dd4..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_168.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_169.png b/packages/SystemUI/res/drawable-xhdpi/remote_169.png Binary files differdeleted file mode 100644 index 564a1610d777..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_169.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_17.png b/packages/SystemUI/res/drawable-xhdpi/remote_17.png Binary files differdeleted file mode 100644 index 0703e1a183aa..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_17.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_170.png b/packages/SystemUI/res/drawable-xhdpi/remote_170.png Binary files differdeleted file mode 100644 index 0411f94479e2..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_170.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_171.png b/packages/SystemUI/res/drawable-xhdpi/remote_171.png Binary files differdeleted file mode 100644 index ec141e92e566..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_171.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_172.png b/packages/SystemUI/res/drawable-xhdpi/remote_172.png Binary files differdeleted file mode 100644 index cb9ecaf985b0..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_172.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_173.png b/packages/SystemUI/res/drawable-xhdpi/remote_173.png Binary files differdeleted file mode 100644 index 484ee5128bb8..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_173.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_174.png b/packages/SystemUI/res/drawable-xhdpi/remote_174.png Binary files differdeleted file mode 100644 index 85a31351c800..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_174.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_175.png b/packages/SystemUI/res/drawable-xhdpi/remote_175.png Binary files differdeleted file mode 100644 index edd65074519d..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_175.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_176.png b/packages/SystemUI/res/drawable-xhdpi/remote_176.png Binary files differdeleted file mode 100644 index d95a68b3020f..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_176.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_177.png b/packages/SystemUI/res/drawable-xhdpi/remote_177.png Binary files differdeleted file mode 100644 index 305641f8d83c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_177.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_178.png b/packages/SystemUI/res/drawable-xhdpi/remote_178.png Binary files differdeleted file mode 100644 index 59de0e58446a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_178.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_179.png b/packages/SystemUI/res/drawable-xhdpi/remote_179.png Binary files differdeleted file mode 100644 index 414e548c17f6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_179.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_18.png b/packages/SystemUI/res/drawable-xhdpi/remote_18.png Binary files differdeleted file mode 100644 index 74df1e4520d5..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_18.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_180.png b/packages/SystemUI/res/drawable-xhdpi/remote_180.png Binary files differdeleted file mode 100644 index b5d925c0997e..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_180.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_181.png b/packages/SystemUI/res/drawable-xhdpi/remote_181.png Binary files differdeleted file mode 100644 index e8a71278cc03..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_181.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_182.png b/packages/SystemUI/res/drawable-xhdpi/remote_182.png Binary files differdeleted file mode 100644 index 29c70375de42..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_182.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_183.png b/packages/SystemUI/res/drawable-xhdpi/remote_183.png Binary files differdeleted file mode 100644 index 9491d9467d2d..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_183.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_184.png b/packages/SystemUI/res/drawable-xhdpi/remote_184.png Binary files differdeleted file mode 100644 index 4aa0e3253a83..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_184.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_185.png b/packages/SystemUI/res/drawable-xhdpi/remote_185.png Binary files differdeleted file mode 100644 index 2a0dde86123d..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_185.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_186.png b/packages/SystemUI/res/drawable-xhdpi/remote_186.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_186.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_187.png b/packages/SystemUI/res/drawable-xhdpi/remote_187.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_187.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_188.png b/packages/SystemUI/res/drawable-xhdpi/remote_188.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_188.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_189.png b/packages/SystemUI/res/drawable-xhdpi/remote_189.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_189.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_19.png b/packages/SystemUI/res/drawable-xhdpi/remote_19.png Binary files differdeleted file mode 100644 index 222ea31194af..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_19.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_190.png b/packages/SystemUI/res/drawable-xhdpi/remote_190.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_190.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_191.png b/packages/SystemUI/res/drawable-xhdpi/remote_191.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_191.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_192.png b/packages/SystemUI/res/drawable-xhdpi/remote_192.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_192.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_193.png b/packages/SystemUI/res/drawable-xhdpi/remote_193.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_193.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_194.png b/packages/SystemUI/res/drawable-xhdpi/remote_194.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_194.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_195.png b/packages/SystemUI/res/drawable-xhdpi/remote_195.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_195.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_196.png b/packages/SystemUI/res/drawable-xhdpi/remote_196.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_196.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_197.png b/packages/SystemUI/res/drawable-xhdpi/remote_197.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_197.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_198.png b/packages/SystemUI/res/drawable-xhdpi/remote_198.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_198.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_199.png b/packages/SystemUI/res/drawable-xhdpi/remote_199.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_199.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_2.png b/packages/SystemUI/res/drawable-xhdpi/remote_2.png Binary files differdeleted file mode 100644 index fb3f7ef1364c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_2.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_20.png b/packages/SystemUI/res/drawable-xhdpi/remote_20.png Binary files differdeleted file mode 100644 index 646587c3e29c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_20.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_200.png b/packages/SystemUI/res/drawable-xhdpi/remote_200.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_200.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_201.png b/packages/SystemUI/res/drawable-xhdpi/remote_201.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_201.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_202.png b/packages/SystemUI/res/drawable-xhdpi/remote_202.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_202.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_203.png b/packages/SystemUI/res/drawable-xhdpi/remote_203.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_203.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_204.png b/packages/SystemUI/res/drawable-xhdpi/remote_204.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_204.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_205.png b/packages/SystemUI/res/drawable-xhdpi/remote_205.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_205.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_206.png b/packages/SystemUI/res/drawable-xhdpi/remote_206.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_206.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_207.png b/packages/SystemUI/res/drawable-xhdpi/remote_207.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_207.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_208.png b/packages/SystemUI/res/drawable-xhdpi/remote_208.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_208.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_209.png b/packages/SystemUI/res/drawable-xhdpi/remote_209.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_209.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_21.png b/packages/SystemUI/res/drawable-xhdpi/remote_21.png Binary files differdeleted file mode 100644 index 5858ba92ce7a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_21.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_210.png b/packages/SystemUI/res/drawable-xhdpi/remote_210.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_210.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_211.png b/packages/SystemUI/res/drawable-xhdpi/remote_211.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_211.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_212.png b/packages/SystemUI/res/drawable-xhdpi/remote_212.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_212.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_213.png b/packages/SystemUI/res/drawable-xhdpi/remote_213.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_213.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_214.png b/packages/SystemUI/res/drawable-xhdpi/remote_214.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_214.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_215.png b/packages/SystemUI/res/drawable-xhdpi/remote_215.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_215.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_216.png b/packages/SystemUI/res/drawable-xhdpi/remote_216.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_216.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_217.png b/packages/SystemUI/res/drawable-xhdpi/remote_217.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_217.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_218.png b/packages/SystemUI/res/drawable-xhdpi/remote_218.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_218.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_219.png b/packages/SystemUI/res/drawable-xhdpi/remote_219.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_219.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_22.png b/packages/SystemUI/res/drawable-xhdpi/remote_22.png Binary files differdeleted file mode 100644 index 197480232386..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_22.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_220.png b/packages/SystemUI/res/drawable-xhdpi/remote_220.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_220.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_221.png b/packages/SystemUI/res/drawable-xhdpi/remote_221.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_221.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_222.png b/packages/SystemUI/res/drawable-xhdpi/remote_222.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_222.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_223.png b/packages/SystemUI/res/drawable-xhdpi/remote_223.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_223.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_224.png b/packages/SystemUI/res/drawable-xhdpi/remote_224.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_224.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_225.png b/packages/SystemUI/res/drawable-xhdpi/remote_225.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_225.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_226.png b/packages/SystemUI/res/drawable-xhdpi/remote_226.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_226.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_227.png b/packages/SystemUI/res/drawable-xhdpi/remote_227.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_227.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_228.png b/packages/SystemUI/res/drawable-xhdpi/remote_228.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_228.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_229.png b/packages/SystemUI/res/drawable-xhdpi/remote_229.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_229.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_23.png b/packages/SystemUI/res/drawable-xhdpi/remote_23.png Binary files differdeleted file mode 100644 index 96b7c3546d76..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_23.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_230.png b/packages/SystemUI/res/drawable-xhdpi/remote_230.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_230.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_231.png b/packages/SystemUI/res/drawable-xhdpi/remote_231.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_231.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_232.png b/packages/SystemUI/res/drawable-xhdpi/remote_232.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_232.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_233.png b/packages/SystemUI/res/drawable-xhdpi/remote_233.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_233.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_234.png b/packages/SystemUI/res/drawable-xhdpi/remote_234.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_234.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_235.png b/packages/SystemUI/res/drawable-xhdpi/remote_235.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_235.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_236.png b/packages/SystemUI/res/drawable-xhdpi/remote_236.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_236.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_237.png b/packages/SystemUI/res/drawable-xhdpi/remote_237.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_237.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_238.png b/packages/SystemUI/res/drawable-xhdpi/remote_238.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_238.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_239.png b/packages/SystemUI/res/drawable-xhdpi/remote_239.png Binary files differdeleted file mode 100644 index 5bda52e3b089..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_239.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_24.png b/packages/SystemUI/res/drawable-xhdpi/remote_24.png Binary files differdeleted file mode 100644 index 0437200d773a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_24.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_25.png b/packages/SystemUI/res/drawable-xhdpi/remote_25.png Binary files differdeleted file mode 100644 index 60b0f154369c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_25.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_26.png b/packages/SystemUI/res/drawable-xhdpi/remote_26.png Binary files differdeleted file mode 100644 index c34ed97b5c93..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_26.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_27.png b/packages/SystemUI/res/drawable-xhdpi/remote_27.png Binary files differdeleted file mode 100644 index 1a83664c5ebc..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_27.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_28.png b/packages/SystemUI/res/drawable-xhdpi/remote_28.png Binary files differdeleted file mode 100644 index a3685ad396ab..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_28.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_29.png b/packages/SystemUI/res/drawable-xhdpi/remote_29.png Binary files differdeleted file mode 100644 index f7135eb8321a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_29.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_3.png b/packages/SystemUI/res/drawable-xhdpi/remote_3.png Binary files differdeleted file mode 100644 index 937da65ea9a1..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_3.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_30.png b/packages/SystemUI/res/drawable-xhdpi/remote_30.png Binary files differdeleted file mode 100644 index 718cf524f151..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_30.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_31.png b/packages/SystemUI/res/drawable-xhdpi/remote_31.png Binary files differdeleted file mode 100644 index c0b55df68f75..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_31.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_32.png b/packages/SystemUI/res/drawable-xhdpi/remote_32.png Binary files differdeleted file mode 100644 index 7a1ce9fd43c6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_32.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_33.png b/packages/SystemUI/res/drawable-xhdpi/remote_33.png Binary files differdeleted file mode 100644 index 5428bcf327ef..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_33.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_34.png b/packages/SystemUI/res/drawable-xhdpi/remote_34.png Binary files differdeleted file mode 100644 index 264efe87f164..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_34.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_35.png b/packages/SystemUI/res/drawable-xhdpi/remote_35.png Binary files differdeleted file mode 100644 index a5c450f4bab6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_35.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_36.png b/packages/SystemUI/res/drawable-xhdpi/remote_36.png Binary files differdeleted file mode 100644 index 3e469e4a3b36..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_36.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_37.png b/packages/SystemUI/res/drawable-xhdpi/remote_37.png Binary files differdeleted file mode 100644 index 124ebe4f1599..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_37.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_38.png b/packages/SystemUI/res/drawable-xhdpi/remote_38.png Binary files differdeleted file mode 100644 index b2b48448c568..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_38.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_39.png b/packages/SystemUI/res/drawable-xhdpi/remote_39.png Binary files differdeleted file mode 100644 index a6d1733b1d6b..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_39.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_4.png b/packages/SystemUI/res/drawable-xhdpi/remote_4.png Binary files differdeleted file mode 100644 index c282f406839b..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_4.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_40.png b/packages/SystemUI/res/drawable-xhdpi/remote_40.png Binary files differdeleted file mode 100644 index 4cd615c16b93..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_40.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_41.png b/packages/SystemUI/res/drawable-xhdpi/remote_41.png Binary files differdeleted file mode 100644 index c746ae0fcc82..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_41.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_42.png b/packages/SystemUI/res/drawable-xhdpi/remote_42.png Binary files differdeleted file mode 100644 index a93f1984dce4..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_42.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_43.png b/packages/SystemUI/res/drawable-xhdpi/remote_43.png Binary files differdeleted file mode 100644 index 966e563e3fa2..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_43.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_44.png b/packages/SystemUI/res/drawable-xhdpi/remote_44.png Binary files differdeleted file mode 100644 index beb7031cd7aa..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_44.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_45.png b/packages/SystemUI/res/drawable-xhdpi/remote_45.png Binary files differdeleted file mode 100644 index 718e1678af57..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_45.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_46.png b/packages/SystemUI/res/drawable-xhdpi/remote_46.png Binary files differdeleted file mode 100644 index aa54ddbf61d1..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_46.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_47.png b/packages/SystemUI/res/drawable-xhdpi/remote_47.png Binary files differdeleted file mode 100644 index 1d112707ea68..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_47.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_48.png b/packages/SystemUI/res/drawable-xhdpi/remote_48.png Binary files differdeleted file mode 100644 index ab31163c9096..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_48.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_49.png b/packages/SystemUI/res/drawable-xhdpi/remote_49.png Binary files differdeleted file mode 100644 index 219b7f645484..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_49.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_5.png b/packages/SystemUI/res/drawable-xhdpi/remote_5.png Binary files differdeleted file mode 100644 index 15f69e19c75a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_5.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_50.png b/packages/SystemUI/res/drawable-xhdpi/remote_50.png Binary files differdeleted file mode 100644 index 8a9725fb6777..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_50.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_51.png b/packages/SystemUI/res/drawable-xhdpi/remote_51.png Binary files differdeleted file mode 100644 index bc839cfc7fbc..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_51.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_52.png b/packages/SystemUI/res/drawable-xhdpi/remote_52.png Binary files differdeleted file mode 100644 index 7bab6e54ad23..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_52.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_53.png b/packages/SystemUI/res/drawable-xhdpi/remote_53.png Binary files differdeleted file mode 100644 index 34ab855027f6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_53.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_54.png b/packages/SystemUI/res/drawable-xhdpi/remote_54.png Binary files differdeleted file mode 100644 index 5bd9f59afe3b..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_54.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_55.png b/packages/SystemUI/res/drawable-xhdpi/remote_55.png Binary files differdeleted file mode 100644 index 1ff17f4c0aff..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_55.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_56.png b/packages/SystemUI/res/drawable-xhdpi/remote_56.png Binary files differdeleted file mode 100644 index d57e067639a9..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_56.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_57.png b/packages/SystemUI/res/drawable-xhdpi/remote_57.png Binary files differdeleted file mode 100644 index a1bdae110893..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_57.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_58.png b/packages/SystemUI/res/drawable-xhdpi/remote_58.png Binary files differdeleted file mode 100644 index c8bc6a4548ad..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_58.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_59.png b/packages/SystemUI/res/drawable-xhdpi/remote_59.png Binary files differdeleted file mode 100644 index 526a24ea965e..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_59.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_6.png b/packages/SystemUI/res/drawable-xhdpi/remote_6.png Binary files differdeleted file mode 100644 index 2b6732fca80e..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_6.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_60.png b/packages/SystemUI/res/drawable-xhdpi/remote_60.png Binary files differdeleted file mode 100644 index 080619ecbc7f..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_60.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_61.png b/packages/SystemUI/res/drawable-xhdpi/remote_61.png Binary files differdeleted file mode 100644 index 5932a8ca2952..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_61.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_62.png b/packages/SystemUI/res/drawable-xhdpi/remote_62.png Binary files differdeleted file mode 100644 index d1233dd34f3c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_62.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_63.png b/packages/SystemUI/res/drawable-xhdpi/remote_63.png Binary files differdeleted file mode 100644 index 4f230c7cad23..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_63.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_64.png b/packages/SystemUI/res/drawable-xhdpi/remote_64.png Binary files differdeleted file mode 100644 index 6b89fcbdcefd..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_64.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_65.png b/packages/SystemUI/res/drawable-xhdpi/remote_65.png Binary files differdeleted file mode 100644 index 87597b1fae43..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_65.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_66.png b/packages/SystemUI/res/drawable-xhdpi/remote_66.png Binary files differdeleted file mode 100644 index 0ee8c1e4ab81..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_66.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_67.png b/packages/SystemUI/res/drawable-xhdpi/remote_67.png Binary files differdeleted file mode 100644 index 9aca8fddd52c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_67.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_68.png b/packages/SystemUI/res/drawable-xhdpi/remote_68.png Binary files differdeleted file mode 100644 index 5f263aedff0c..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_68.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_69.png b/packages/SystemUI/res/drawable-xhdpi/remote_69.png Binary files differdeleted file mode 100644 index 1a22b61407c6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_69.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_7.png b/packages/SystemUI/res/drawable-xhdpi/remote_7.png Binary files differdeleted file mode 100644 index 9d9d699a6560..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_7.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_70.png b/packages/SystemUI/res/drawable-xhdpi/remote_70.png Binary files differdeleted file mode 100644 index 0372c50f3a8a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_70.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_71.png b/packages/SystemUI/res/drawable-xhdpi/remote_71.png Binary files differdeleted file mode 100644 index 854e3e2b4bc7..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_71.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_72.png b/packages/SystemUI/res/drawable-xhdpi/remote_72.png Binary files differdeleted file mode 100644 index 691962448e30..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_72.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_73.png b/packages/SystemUI/res/drawable-xhdpi/remote_73.png Binary files differdeleted file mode 100644 index d8e9ae182e71..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_73.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_74.png b/packages/SystemUI/res/drawable-xhdpi/remote_74.png Binary files differdeleted file mode 100644 index 24e5b6abcdf0..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_74.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_75.png b/packages/SystemUI/res/drawable-xhdpi/remote_75.png Binary files differdeleted file mode 100644 index 369a3a9c0afd..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_75.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_76.png b/packages/SystemUI/res/drawable-xhdpi/remote_76.png Binary files differdeleted file mode 100644 index 96824c6dc575..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_76.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_77.png b/packages/SystemUI/res/drawable-xhdpi/remote_77.png Binary files differdeleted file mode 100644 index dd60ccad6ab3..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_77.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_78.png b/packages/SystemUI/res/drawable-xhdpi/remote_78.png Binary files differdeleted file mode 100644 index aa3460bfc890..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_78.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_79.png b/packages/SystemUI/res/drawable-xhdpi/remote_79.png Binary files differdeleted file mode 100644 index 9a60e3c9b629..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_79.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_8.png b/packages/SystemUI/res/drawable-xhdpi/remote_8.png Binary files differdeleted file mode 100644 index b73c7efb6edd..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_8.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_80.png b/packages/SystemUI/res/drawable-xhdpi/remote_80.png Binary files differdeleted file mode 100644 index cbf883c7972e..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_80.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_81.png b/packages/SystemUI/res/drawable-xhdpi/remote_81.png Binary files differdeleted file mode 100644 index 11a6add24bde..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_81.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_82.png b/packages/SystemUI/res/drawable-xhdpi/remote_82.png Binary files differdeleted file mode 100644 index e05105d9b8ea..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_82.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_83.png b/packages/SystemUI/res/drawable-xhdpi/remote_83.png Binary files differdeleted file mode 100644 index 57813aac5f0a..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_83.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_84.png b/packages/SystemUI/res/drawable-xhdpi/remote_84.png Binary files differdeleted file mode 100644 index 0f6f0fe6208b..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_84.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_85.png b/packages/SystemUI/res/drawable-xhdpi/remote_85.png Binary files differdeleted file mode 100644 index ada83ec852f4..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_85.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_86.png b/packages/SystemUI/res/drawable-xhdpi/remote_86.png Binary files differdeleted file mode 100644 index 442dd5181e67..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_86.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_87.png b/packages/SystemUI/res/drawable-xhdpi/remote_87.png Binary files differdeleted file mode 100644 index bdb4962a72a2..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_87.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_88.png b/packages/SystemUI/res/drawable-xhdpi/remote_88.png Binary files differdeleted file mode 100644 index b31800298bfd..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_88.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_89.png b/packages/SystemUI/res/drawable-xhdpi/remote_89.png Binary files differdeleted file mode 100644 index c4ed874495d6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_89.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_9.png b/packages/SystemUI/res/drawable-xhdpi/remote_9.png Binary files differdeleted file mode 100644 index ce5041f64f4e..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_90.png b/packages/SystemUI/res/drawable-xhdpi/remote_90.png Binary files differdeleted file mode 100644 index 6a662f9d65a7..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_90.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_91.png b/packages/SystemUI/res/drawable-xhdpi/remote_91.png Binary files differdeleted file mode 100644 index 21be887a1234..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_91.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_92.png b/packages/SystemUI/res/drawable-xhdpi/remote_92.png Binary files differdeleted file mode 100644 index 1bc536165bc8..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_92.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_93.png b/packages/SystemUI/res/drawable-xhdpi/remote_93.png Binary files differdeleted file mode 100644 index 76495ac70941..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_93.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_94.png b/packages/SystemUI/res/drawable-xhdpi/remote_94.png Binary files differdeleted file mode 100644 index 081c84b9f011..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_94.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_95.png b/packages/SystemUI/res/drawable-xhdpi/remote_95.png Binary files differdeleted file mode 100644 index e9c27a8216b6..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_95.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_96.png b/packages/SystemUI/res/drawable-xhdpi/remote_96.png Binary files differdeleted file mode 100644 index 13696031d6dc..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_96.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_97.png b/packages/SystemUI/res/drawable-xhdpi/remote_97.png Binary files differdeleted file mode 100644 index fbd14583d989..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_97.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_98.png b/packages/SystemUI/res/drawable-xhdpi/remote_98.png Binary files differdeleted file mode 100644 index ccdd7a7aecca..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_98.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_99.png b/packages/SystemUI/res/drawable-xhdpi/remote_99.png Binary files differdeleted file mode 100644 index f3cb4db410cb..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/remote_99.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/ic_dnd.xml b/packages/SystemUI/res/drawable/ic_dnd.xml index 17ecf217b86b..e658e687821b 100644 --- a/packages/SystemUI/res/drawable/ic_dnd.xml +++ b/packages/SystemUI/res/drawable/ic_dnd.xml @@ -17,7 +17,8 @@ android:height="24dp" android:viewportHeight="48.0" android:viewportWidth="48.0" - android:width="24dp" > + android:width="24dp" + android:tint="?android:attr/colorControlNormal"> <path android:fillColor="#FFFFFFFF" diff --git a/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml b/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml index 487597454e27..0515b35fb875 100644 --- a/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml +++ b/packages/SystemUI/res/drawable/ic_dnd_total_silence.xml @@ -17,7 +17,8 @@ android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" - android:width="24dp" > + android:width="24dp" + android:tint="?android:attr/colorControlNormal"> <path android:fillColor="#FFFFFFFF" diff --git a/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml b/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml index 5aecebae1865..169cc71722a2 100644 --- a/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml +++ b/packages/SystemUI/res/drawable/ic_invert_colors_enable.xml @@ -16,7 +16,6 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:name="root" - android:alpha="0.3" android:height="48dp" android:width="48dp" android:viewportHeight="48" diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml index 236fdac09c4b..5e7cd974818a 100644 --- a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml +++ b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml @@ -17,7 +17,8 @@ Copyright (C) 2014 The Android Open Source Project android:width="6.0dp" android:height="32dp" android:viewportWidth="6.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?android:attr/textColorSecondary"> <path android:fillColor="#FFFFFFFF" android:pathData="M6.000000,15.700000l-3.000000,5.599999 -3.000000,-5.599999z"/> diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml index c510972a5df8..0dca1db32f88 100644 --- a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml +++ b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml @@ -17,7 +17,8 @@ Copyright (C) 2014 The Android Open Source Project android:width="6.0dp" android:height="32dp" android:viewportWidth="6.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?android:attr/textColorSecondary"> <path android:fillColor="#FFFFFFFF" android:pathData="M0.000000,13.700000l3.000000,-5.700000 3.000000,5.700000z"/> diff --git a/packages/SystemUI/res/drawable/segmented_buttons_background.xml b/packages/SystemUI/res/drawable/segmented_buttons_background.xml index b243dc7ce8c0..755c917cf20c 100644 --- a/packages/SystemUI/res/drawable/segmented_buttons_background.xml +++ b/packages/SystemUI/res/drawable/segmented_buttons_background.xml @@ -17,6 +17,6 @@ <corners android:radius="@dimen/borderless_button_radius" /> - <solid android:color="@color/segmented_buttons_background" /> + <solid android:color="?android:attr/colorPrimaryDark" /> -</shape>
\ No newline at end of file +</shape> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml index d7463a446657..be9a7e266c6f 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="8.5dp" - android:height="17dp" - android:viewportWidth="12.0" - android:viewportHeight="24.0"> + android:width="17dp" + android:height="17dp" + android:viewportWidth="12.0" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml index 6309b6d9903b..fd7a65841129 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="9.208dp" + android:width="17dp" android:height="17dp" android:viewportWidth="13.0" - android:viewportHeight="24.0"> + android:viewportHeight="13.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml index 4067ae5b4800..02c4ab6161c6 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="8.5dp" + android:width="17dp" android:height="17dp" android:viewportWidth="12.0" - android:viewportHeight="24.0"> + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml index 3cdd3e104bfb..daf40618c24a 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml @@ -14,10 +14,10 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17.0dp" + android:width="25.5dp" android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportWidth="18.0" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml index acaa9b1c2be8..cd0cc6585391 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="3.541dp" + android:width="7.083dp" android:height="17dp" android:viewportWidth="5.0" - android:viewportHeight="24.0"> + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml index 7985237d8a44..92ed49c71189 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="4.958dp" + android:width="9.154dp" android:height="17dp" android:viewportWidth="7.0" - android:viewportHeight="24.0"> + android:viewportHeight="13"> <path android:fillColor="#FFFFFFFF" android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml index fda87612582e..ca61b6f0299c 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="4.25dp" + android:width="9.5dp" android:height="17dp" android:viewportWidth="6.0" - android:viewportHeight="24.0"> + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml index c08ff20c54fc..add96b4352e8 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="9.208dp" + android:width="18.417dp" android:height="17dp" - android:viewportWidth="13.0" - android:viewportHeight="24.0"> + android:viewportWidth="13" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml index db18fad637e7..8811d2f9b7ba 100644 --- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml +++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml @@ -14,10 +14,10 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17.0dp" + android:width="25.0dp" android:height="17.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportWidth="18.0" + android:viewportHeight="12.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_roaming.xml b/packages/SystemUI/res/drawable/stat_sys_roaming.xml index 4baa472acb88..363e231cf03c 100644 --- a/packages/SystemUI/res/drawable/stat_sys_roaming.xml +++ b/packages/SystemUI/res/drawable/stat_sys_roaming.xml @@ -14,10 +14,10 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="8.5dp" + android:width="4.25dp" android:height="17dp" android:viewportWidth="6.0" - android:viewportHeight="12.0"> + android:viewportHeight="24.0"> <path android:fillColor="#FFFFFFFF" android:pathData="M2.800000,7.900000l-1.000000,0.000000L1.800000,11.000000L0.200000,11.000000L0.200000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S4.800000,7.200000 4.400000,7.400000l1.500000,3.500000L5.900000,11.000000L4.100000,11.000000L2.800000,7.900000zM1.800000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000S4.000000,5.600000 4.000000,5.200000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S3.300000,3.800000 2.900000,3.800000L1.800000,3.800000L1.800000,6.500000z"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml new file mode 100644 index 000000000000..f4e8af468b76 --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml @@ -0,0 +1,42 @@ +<!-- + 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:width="18.41dp" + android:height="17dp" + android:viewportWidth="26.0" + android:viewportHeight="24.0"> + <path + android:fillColor="?attr/backgroundColor" + android:pathData="M21.0,8.5 + c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79 + C25.1,5.96 20.26,2.0 13.0,2.0 + S0.9,5.9 0.42,6.32 + l12.57,15.6 4.21,-5.17 + c-0.76,-0.87 -1.22,-2.0 -1.22,-3.25 + c0.0,-2.76 2.24,-5.0 5.0,-5.0z" + android:fillAlpha=".3"/> + <path + android:fillColor="?attr/backgroundColor" + android:pathData="M21.0,10.0 + c-1.93,0.0 -3.5,1.57 -3.5,3.5l1.75,0.0 + c0.0,-0.9 0.78,-1.75 1.75,-1.75s1.7,0.78 1.75,1.75 + c0.0,0.48 -0.2,0.92 -0.51,1.24l-1.09,1.1 + c-0.6,0.63 -1.02,1.51 -1.02,2.47l0.0,0.44l1.75,0.0 + c0.0,-1.3 0.39,-1.84 1.03,-2.47l0.78,-0.8 + c0.5,-0.5 0.82,-1.2 0.82,-1.97 + C24.5,11.57 22.93,10.0 21.0,10.0z + m-0.95,11.95l1.9,0.0l0.0,-1.9l-1.9,0.0l0.0,1.9z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml index 5169de46ea29..c1856fa30e7e 100644 --- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml +++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml @@ -20,5 +20,8 @@ Copyright (C) 2014 The Android Open Source Project android:viewportHeight="24.0"> <path android:fillColor="?attr/backgroundColor" - android:pathData="M13.000000,2.000000C7.700000,2.000000 3.700000,3.900000 0.400000,6.400000L13.000000,22.000000L25.600000,6.500000C22.299999,4.000000 18.299999,2.000000 13.000000,2.000000zM13.000000,18.600000L3.300000,7.000000l0.000000,0.000000l0.000000,0.000000C6.000000,5.300000 8.700000,4.000000 13.000000,4.000000s7.000000,1.400000 9.700000,3.000000l0.000000,0.000000l0.000000,0.000000L13.000000,18.600000z"/> + android:pathData="M17.500000,16.500000L5.800000,3.400000c0.000000,0.000000 0.000000,0.000000 0.000000,0.000000l-2.700000,-3.000000L1.600000,1.800000l2.200000,2.500000c-2.000000,1.000000 -3.200000,2.000000 -3.400000,2.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l3.200000,-3.900000l2.400000,2.700000l1.500000,-1.400000L17.500000,16.500000L17.500000,16.500000z"/> + <path + android:fillColor="?attr/backgroundColor" + android:pathData="M25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000c-1.900000,0.000000 -3.600000,0.300000 -5.200000,0.700000L18.700001,15.000000L25.600000,6.500000z"/> </vector> diff --git a/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml b/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml deleted file mode 100644 index d46108ae6ffc..000000000000 --- a/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml +++ /dev/null @@ -1,259 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<animation-list xmlns:android="http://schemas.android.com/apk/res/android" - android:oneshot="false"> - - <item android:drawable="@drawable/remote_0" android:duration="13" /> - <item android:drawable="@drawable/remote_1" android:duration="13" /> - <item android:drawable="@drawable/remote_2" android:duration="13" /> - <item android:drawable="@drawable/remote_3" android:duration="13" /> - <item android:drawable="@drawable/remote_4" android:duration="13" /> - <item android:drawable="@drawable/remote_5" android:duration="13" /> - <item android:drawable="@drawable/remote_6" android:duration="13" /> - <item android:drawable="@drawable/remote_7" android:duration="13" /> - <item android:drawable="@drawable/remote_8" android:duration="13" /> - <item android:drawable="@drawable/remote_9" android:duration="13" /> - <item android:drawable="@drawable/remote_10" android:duration="13" /> - <item android:drawable="@drawable/remote_11" android:duration="13" /> - <item android:drawable="@drawable/remote_12" android:duration="13" /> - <item android:drawable="@drawable/remote_13" android:duration="13" /> - <item android:drawable="@drawable/remote_14" android:duration="13" /> - <item android:drawable="@drawable/remote_15" android:duration="13" /> - <item android:drawable="@drawable/remote_16" android:duration="13" /> - <item android:drawable="@drawable/remote_17" android:duration="13" /> - <item android:drawable="@drawable/remote_18" android:duration="13" /> - <item android:drawable="@drawable/remote_19" android:duration="13" /> - <item android:drawable="@drawable/remote_20" android:duration="13" /> - <item android:drawable="@drawable/remote_21" android:duration="13" /> - <item android:drawable="@drawable/remote_22" android:duration="13" /> - <item android:drawable="@drawable/remote_23" android:duration="13" /> - <item android:drawable="@drawable/remote_24" android:duration="13" /> - <item android:drawable="@drawable/remote_25" android:duration="13" /> - <item android:drawable="@drawable/remote_26" android:duration="13" /> - <item android:drawable="@drawable/remote_27" android:duration="13" /> - <item android:drawable="@drawable/remote_28" android:duration="13" /> - <item android:drawable="@drawable/remote_29" android:duration="13" /> - <item android:drawable="@drawable/remote_30" android:duration="13" /> - <item android:drawable="@drawable/remote_31" android:duration="13" /> - <item android:drawable="@drawable/remote_32" android:duration="13" /> - <item android:drawable="@drawable/remote_33" android:duration="13" /> - <item android:drawable="@drawable/remote_34" android:duration="13" /> - <item android:drawable="@drawable/remote_35" android:duration="13" /> - <item android:drawable="@drawable/remote_36" android:duration="13" /> - <item android:drawable="@drawable/remote_37" android:duration="13" /> - <item android:drawable="@drawable/remote_38" android:duration="13" /> - <item android:drawable="@drawable/remote_39" android:duration="13" /> - <item android:drawable="@drawable/remote_40" android:duration="13" /> - <item android:drawable="@drawable/remote_41" android:duration="13" /> - <item android:drawable="@drawable/remote_42" android:duration="13" /> - <item android:drawable="@drawable/remote_43" android:duration="13" /> - <item android:drawable="@drawable/remote_44" android:duration="13" /> - <item android:drawable="@drawable/remote_45" android:duration="13" /> - <item android:drawable="@drawable/remote_46" android:duration="13" /> - <item android:drawable="@drawable/remote_47" android:duration="13" /> - <item android:drawable="@drawable/remote_48" android:duration="13" /> - <item android:drawable="@drawable/remote_49" android:duration="13" /> - <item android:drawable="@drawable/remote_50" android:duration="13" /> - <item android:drawable="@drawable/remote_51" android:duration="13" /> - <item android:drawable="@drawable/remote_52" android:duration="13" /> - <item android:drawable="@drawable/remote_53" android:duration="13" /> - <item android:drawable="@drawable/remote_54" android:duration="13" /> - <item android:drawable="@drawable/remote_55" android:duration="13" /> - <item android:drawable="@drawable/remote_56" android:duration="13" /> - <item android:drawable="@drawable/remote_57" android:duration="13" /> - <item android:drawable="@drawable/remote_58" android:duration="13" /> - <item android:drawable="@drawable/remote_59" android:duration="13" /> - <item android:drawable="@drawable/remote_60" android:duration="13" /> - <item android:drawable="@drawable/remote_61" android:duration="13" /> - <item android:drawable="@drawable/remote_62" android:duration="13" /> - <item android:drawable="@drawable/remote_63" android:duration="13" /> - <item android:drawable="@drawable/remote_64" android:duration="13" /> - <item android:drawable="@drawable/remote_65" android:duration="13" /> - <item android:drawable="@drawable/remote_66" android:duration="13" /> - <item android:drawable="@drawable/remote_67" android:duration="13" /> - <item android:drawable="@drawable/remote_68" android:duration="13" /> - <item android:drawable="@drawable/remote_69" android:duration="13" /> - <item android:drawable="@drawable/remote_70" android:duration="13" /> - <item android:drawable="@drawable/remote_71" android:duration="13" /> - <item android:drawable="@drawable/remote_72" android:duration="13" /> - <item android:drawable="@drawable/remote_73" android:duration="13" /> - <item android:drawable="@drawable/remote_74" android:duration="13" /> - <item android:drawable="@drawable/remote_75" android:duration="13" /> - <item android:drawable="@drawable/remote_76" android:duration="13" /> - <item android:drawable="@drawable/remote_77" android:duration="13" /> - <item android:drawable="@drawable/remote_78" android:duration="13" /> - <item android:drawable="@drawable/remote_79" android:duration="13" /> - <item android:drawable="@drawable/remote_80" android:duration="13" /> - <item android:drawable="@drawable/remote_81" android:duration="13" /> - <item android:drawable="@drawable/remote_82" android:duration="13" /> - <item android:drawable="@drawable/remote_83" android:duration="13" /> - <item android:drawable="@drawable/remote_84" android:duration="13" /> - <item android:drawable="@drawable/remote_85" android:duration="13" /> - <item android:drawable="@drawable/remote_86" android:duration="13" /> - <item android:drawable="@drawable/remote_87" android:duration="13" /> - <item android:drawable="@drawable/remote_88" android:duration="13" /> - <item android:drawable="@drawable/remote_89" android:duration="13" /> - <item android:drawable="@drawable/remote_90" android:duration="13" /> - <item android:drawable="@drawable/remote_91" android:duration="13" /> - <item android:drawable="@drawable/remote_92" android:duration="13" /> - <item android:drawable="@drawable/remote_93" android:duration="13" /> - <item android:drawable="@drawable/remote_94" android:duration="13" /> - <item android:drawable="@drawable/remote_95" android:duration="13" /> - <item android:drawable="@drawable/remote_96" android:duration="13" /> - <item android:drawable="@drawable/remote_97" android:duration="13" /> - <item android:drawable="@drawable/remote_98" android:duration="13" /> - <item android:drawable="@drawable/remote_99" android:duration="13" /> - <item android:drawable="@drawable/remote_100" android:duration="13" /> - <item android:drawable="@drawable/remote_101" android:duration="13" /> - <item android:drawable="@drawable/remote_102" android:duration="13" /> - <item android:drawable="@drawable/remote_103" android:duration="13" /> - <item android:drawable="@drawable/remote_104" android:duration="13" /> - <item android:drawable="@drawable/remote_105" android:duration="13" /> - <item android:drawable="@drawable/remote_106" android:duration="13" /> - <item android:drawable="@drawable/remote_107" android:duration="13" /> - <item android:drawable="@drawable/remote_108" android:duration="13" /> - <item android:drawable="@drawable/remote_109" android:duration="13" /> - <item android:drawable="@drawable/remote_110" android:duration="13" /> - <item android:drawable="@drawable/remote_111" android:duration="13" /> - <item android:drawable="@drawable/remote_112" android:duration="13" /> - <item android:drawable="@drawable/remote_113" android:duration="13" /> - <item android:drawable="@drawable/remote_114" android:duration="13" /> - <item android:drawable="@drawable/remote_115" android:duration="13" /> - <item android:drawable="@drawable/remote_116" android:duration="13" /> - <item android:drawable="@drawable/remote_117" android:duration="13" /> - <item android:drawable="@drawable/remote_118" android:duration="13" /> - <item android:drawable="@drawable/remote_119" android:duration="13" /> - <item android:drawable="@drawable/remote_120" android:duration="13" /> - <item android:drawable="@drawable/remote_121" android:duration="13" /> - <item android:drawable="@drawable/remote_122" android:duration="13" /> - <item android:drawable="@drawable/remote_123" android:duration="13" /> - <item android:drawable="@drawable/remote_124" android:duration="13" /> - <item android:drawable="@drawable/remote_125" android:duration="13" /> - <item android:drawable="@drawable/remote_126" android:duration="13" /> - <item android:drawable="@drawable/remote_127" android:duration="13" /> - <item android:drawable="@drawable/remote_128" android:duration="13" /> - <item android:drawable="@drawable/remote_129" android:duration="13" /> - <item android:drawable="@drawable/remote_130" android:duration="13" /> - <item android:drawable="@drawable/remote_131" android:duration="13" /> - <item android:drawable="@drawable/remote_132" android:duration="13" /> - <item android:drawable="@drawable/remote_133" android:duration="13" /> - <item android:drawable="@drawable/remote_134" android:duration="13" /> - <item android:drawable="@drawable/remote_135" android:duration="13" /> - <item android:drawable="@drawable/remote_136" android:duration="13" /> - <item android:drawable="@drawable/remote_137" android:duration="13" /> - <item android:drawable="@drawable/remote_138" android:duration="13" /> - <item android:drawable="@drawable/remote_139" android:duration="13" /> - <item android:drawable="@drawable/remote_140" android:duration="13" /> - <item android:drawable="@drawable/remote_141" android:duration="13" /> - <item android:drawable="@drawable/remote_142" android:duration="13" /> - <item android:drawable="@drawable/remote_143" android:duration="13" /> - <item android:drawable="@drawable/remote_144" android:duration="13" /> - <item android:drawable="@drawable/remote_145" android:duration="13" /> - <item android:drawable="@drawable/remote_146" android:duration="13" /> - <item android:drawable="@drawable/remote_147" android:duration="13" /> - <item android:drawable="@drawable/remote_148" android:duration="13" /> - <item android:drawable="@drawable/remote_149" android:duration="13" /> - <item android:drawable="@drawable/remote_150" android:duration="13" /> - <item android:drawable="@drawable/remote_151" android:duration="13" /> - <item android:drawable="@drawable/remote_152" android:duration="13" /> - <item android:drawable="@drawable/remote_153" android:duration="13" /> - <item android:drawable="@drawable/remote_154" android:duration="13" /> - <item android:drawable="@drawable/remote_155" android:duration="13" /> - <item android:drawable="@drawable/remote_156" android:duration="13" /> - <item android:drawable="@drawable/remote_157" android:duration="13" /> - <item android:drawable="@drawable/remote_158" android:duration="13" /> - <item android:drawable="@drawable/remote_159" android:duration="13" /> - <item android:drawable="@drawable/remote_160" android:duration="13" /> - <item android:drawable="@drawable/remote_161" android:duration="13" /> - <item android:drawable="@drawable/remote_162" android:duration="13" /> - <item android:drawable="@drawable/remote_163" android:duration="13" /> - <item android:drawable="@drawable/remote_164" android:duration="13" /> - <item android:drawable="@drawable/remote_165" android:duration="13" /> - <item android:drawable="@drawable/remote_166" android:duration="13" /> - <item android:drawable="@drawable/remote_167" android:duration="13" /> - <item android:drawable="@drawable/remote_168" android:duration="13" /> - <item android:drawable="@drawable/remote_169" android:duration="13" /> - <item android:drawable="@drawable/remote_170" android:duration="13" /> - <item android:drawable="@drawable/remote_171" android:duration="13" /> - <item android:drawable="@drawable/remote_172" android:duration="13" /> - <item android:drawable="@drawable/remote_173" android:duration="13" /> - <item android:drawable="@drawable/remote_174" android:duration="13" /> - <item android:drawable="@drawable/remote_175" android:duration="13" /> - <item android:drawable="@drawable/remote_176" android:duration="13" /> - <item android:drawable="@drawable/remote_177" android:duration="13" /> - <item android:drawable="@drawable/remote_178" android:duration="13" /> - <item android:drawable="@drawable/remote_179" android:duration="13" /> - <item android:drawable="@drawable/remote_180" android:duration="13" /> - <item android:drawable="@drawable/remote_181" android:duration="13" /> - <item android:drawable="@drawable/remote_182" android:duration="13" /> - <item android:drawable="@drawable/remote_183" android:duration="13" /> - <item android:drawable="@drawable/remote_184" android:duration="13" /> - <item android:drawable="@drawable/remote_185" android:duration="13" /> - <item android:drawable="@drawable/remote_186" android:duration="13" /> - <item android:drawable="@drawable/remote_187" android:duration="13" /> - <item android:drawable="@drawable/remote_188" android:duration="13" /> - <item android:drawable="@drawable/remote_189" android:duration="13" /> - <item android:drawable="@drawable/remote_190" android:duration="13" /> - <item android:drawable="@drawable/remote_191" android:duration="13" /> - <item android:drawable="@drawable/remote_192" android:duration="13" /> - <item android:drawable="@drawable/remote_193" android:duration="13" /> - <item android:drawable="@drawable/remote_194" android:duration="13" /> - <item android:drawable="@drawable/remote_195" android:duration="13" /> - <item android:drawable="@drawable/remote_196" android:duration="13" /> - <item android:drawable="@drawable/remote_197" android:duration="13" /> - <item android:drawable="@drawable/remote_198" android:duration="13" /> - <item android:drawable="@drawable/remote_199" android:duration="13" /> - <item android:drawable="@drawable/remote_200" android:duration="13" /> - <item android:drawable="@drawable/remote_201" android:duration="13" /> - <item android:drawable="@drawable/remote_202" android:duration="13" /> - <item android:drawable="@drawable/remote_203" android:duration="13" /> - <item android:drawable="@drawable/remote_204" android:duration="13" /> - <item android:drawable="@drawable/remote_205" android:duration="13" /> - <item android:drawable="@drawable/remote_206" android:duration="13" /> - <item android:drawable="@drawable/remote_207" android:duration="13" /> - <item android:drawable="@drawable/remote_208" android:duration="13" /> - <item android:drawable="@drawable/remote_209" android:duration="13" /> - <item android:drawable="@drawable/remote_210" android:duration="13" /> - <item android:drawable="@drawable/remote_211" android:duration="13" /> - <item android:drawable="@drawable/remote_212" android:duration="13" /> - <item android:drawable="@drawable/remote_213" android:duration="13" /> - <item android:drawable="@drawable/remote_214" android:duration="13" /> - <item android:drawable="@drawable/remote_215" android:duration="13" /> - <item android:drawable="@drawable/remote_216" android:duration="13" /> - <item android:drawable="@drawable/remote_217" android:duration="13" /> - <item android:drawable="@drawable/remote_218" android:duration="13" /> - <item android:drawable="@drawable/remote_219" android:duration="13" /> - <item android:drawable="@drawable/remote_220" android:duration="13" /> - <item android:drawable="@drawable/remote_221" android:duration="13" /> - <item android:drawable="@drawable/remote_222" android:duration="13" /> - <item android:drawable="@drawable/remote_223" android:duration="13" /> - <item android:drawable="@drawable/remote_224" android:duration="13" /> - <item android:drawable="@drawable/remote_225" android:duration="13" /> - <item android:drawable="@drawable/remote_226" android:duration="13" /> - <item android:drawable="@drawable/remote_227" android:duration="13" /> - <item android:drawable="@drawable/remote_228" android:duration="13" /> - <item android:drawable="@drawable/remote_229" android:duration="13" /> - <item android:drawable="@drawable/remote_230" android:duration="13" /> - <item android:drawable="@drawable/remote_231" android:duration="13" /> - <item android:drawable="@drawable/remote_232" android:duration="13" /> - <item android:drawable="@drawable/remote_233" android:duration="13" /> - <item android:drawable="@drawable/remote_234" android:duration="13" /> - <item android:drawable="@drawable/remote_235" android:duration="13" /> - <item android:drawable="@drawable/remote_236" android:duration="13" /> - <item android:drawable="@drawable/remote_237" android:duration="13" /> - <item android:drawable="@drawable/remote_238" android:duration="13" /> - <item android:drawable="@drawable/remote_239" android:duration="13" /> -</animation-list> diff --git a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml deleted file mode 100644 index 2b58fc5a5fd3..000000000000 --- a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml +++ /dev/null @@ -1,20 +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. ---> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - - <stroke android:width="1dp" android:color="#33FFFFFF" /> -</shape> diff --git a/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml deleted file mode 100644 index e247dec3ae27..000000000000 --- a/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml +++ /dev/null @@ -1,23 +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. ---> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - - <gradient - android:startColor="#B2000000" - android:endColor="#00000000" - android:angle="90"/> -</shape> diff --git a/packages/SystemUI/res/drawable/tv_pip_recents_overlay_scrim.xml b/packages/SystemUI/res/drawable/tv_pip_recents_overlay_scrim.xml deleted file mode 100644 index 57bee75165ee..000000000000 --- a/packages/SystemUI/res/drawable/tv_pip_recents_overlay_scrim.xml +++ /dev/null @@ -1,23 +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. ---> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - - <gradient - android:startColor="#80000000" - android:endColor="#00000000" - android:angle="90"/> -</shape> diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml index 33effba53059..6d4365c644e4 100644 --- a/packages/SystemUI/res/layout/mobile_signal_group.xml +++ b/packages/SystemUI/res/layout/mobile_signal_group.xml @@ -63,20 +63,21 @@ systemui:hasOverlappingRendering="false" /> <ImageView - android:id="@+id/mobile_type" + android:id="@+id/mobile_roaming" android:layout_height="wrap_content" android:layout_width="wrap_content" + android:src="@drawable/stat_sys_roaming" + android:contentDescription="@string/accessibility_data_connection_roaming" + android:visibility="gone" /> <ImageView - android:id="@+id/mobile_roaming" + android:id="@+id/mobile_type" android:layout_width="wrap_content" android:layout_height="17dp" - android:paddingStart="22dp" + android:paddingStart="19dp" android:paddingTop="1.5dp" android:paddingBottom="3dp" android:scaleType="fitCenter" - android:src="@drawable/stat_sys_roaming" - android:contentDescription="@string/accessibility_data_connection_roaming" android:visibility="gone" /> </FrameLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index ff22ffb319fb..0c9858dc8397 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -114,6 +114,7 @@ android:layout_height="wrap_content" android:layout_gravity="end|center_vertical" android:layout_weight="1" + android:contentDescription="@string/notification_channel_switch_accessibility" android:background="@null" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml index da7e4d79fc46..5766dc1c5b4f 100644 --- a/packages/SystemUI/res/layout/signal_cluster_view.xml +++ b/packages/SystemUI/res/layout/signal_cluster_view.xml @@ -52,9 +52,54 @@ android:alpha="0.0" /> </FrameLayout> + <ViewStub + android:id="@+id/connected_device_signals_stub" + android:layout="@layout/connected_device_signal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + <LinearLayout + android:id="@+id/mobile_signal_group" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + > + </LinearLayout> + <View + android:id="@+id/wifi_signal_spacer" + android:layout_width="@dimen/status_bar_wifi_signal_spacer_width" + android:layout_height="4dp" + android:visibility="gone" + /> + <FrameLayout + android:id="@+id/no_sims_combo" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:contentDescription="@string/accessibility_no_sims"> + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:theme="@style/DualToneLightTheme" + android:id="@+id/no_sims" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:src="@drawable/stat_sys_no_sims" + /> + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:theme="@style/DualToneDarkTheme" + android:id="@+id/no_sims_dark" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:src="@drawable/stat_sys_no_sims" + android:alpha="0.0" + /> + </FrameLayout> + <View + android:id="@+id/wifi_airplane_spacer" + android:layout_width="@dimen/status_bar_airplane_spacer_width" + android:layout_height="4dp" + android:visibility="gone" + /> <FrameLayout android:layout_height="17dp" - android:layout_width="wrap_content"> + android:layout_width="wrap_content" + android:paddingStart="2dp"> <ImageView android:id="@+id/wifi_in" android:layout_height="wrap_content" @@ -96,50 +141,6 @@ android:layout_width="wrap_content" /> </FrameLayout> - <View - android:id="@+id/wifi_signal_spacer" - android:layout_width="@dimen/status_bar_wifi_signal_spacer_width" - android:layout_height="4dp" - android:visibility="gone" - /> - <ViewStub - android:id="@+id/connected_device_signals_stub" - android:layout="@layout/connected_device_signal" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - <LinearLayout - android:id="@+id/mobile_signal_group" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - > - </LinearLayout> - <FrameLayout - android:id="@+id/no_sims_combo" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:contentDescription="@string/accessibility_no_sims"> - <com.android.systemui.statusbar.AlphaOptimizedImageView - android:theme="@style/DualToneLightTheme" - android:id="@+id/no_sims" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:src="@drawable/stat_sys_no_sims" - /> - <com.android.systemui.statusbar.AlphaOptimizedImageView - android:theme="@style/DualToneDarkTheme" - android:id="@+id/no_sims_dark" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:src="@drawable/stat_sys_no_sims" - android:alpha="0.0" - /> - </FrameLayout> - <View - android:id="@+id/wifi_airplane_spacer" - android:layout_width="@dimen/status_bar_airplane_spacer_width" - android:layout_height="4dp" - android:visibility="gone" - /> <ImageView android:id="@+id/airplane" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/layout/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml deleted file mode 100644 index fe80b9464a01..000000000000 --- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -** -** Copyright 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. -*/ ---> - -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/pip_onboarding" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - <View - android:id="@+id/background" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="#000000" - android:alpha="0" /> - - <ImageView - android:id="@+id/remote" - android:layout_width="72dp" - android:layout_height="273dp" - android:layout_marginTop="136dp" - android:layout_marginStart="304dp" - android:layout_alignParentTop="true" - android:layout_alignParentStart="true" - android:adjustViewBounds="true" - android:src="@drawable/remote" - android:alpha="0" /> - <ImageView - android:id="@+id/remote_button" - android:layout_width="50dp" - android:layout_height="50dp" - android:layout_marginTop="256dp" - android:layout_marginStart="315dp" - android:layout_alignParentTop="true" - android:layout_alignParentStart="true" - android:scaleType="fitXY" - android:src="@drawable/tv_pip_onboarding_remote" - android:alpha="0" /> - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="188dp" - android:layout_marginStart="406dp" - android:layout_alignParentTop="true" - android:layout_alignParentStart="true" - android:fontFamily="sans-serif" - android:textSize="24sp" - android:textColor="#EEEEEE" - android:text="@string/pip_onboarding_title" - android:alpha="0" /> - <TextView - android:id="@+id/description" - android:layout_width="200dp" - android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:layout_marginStart="408dp" - android:layout_below="@id/title" - android:layout_alignParentStart="true" - android:fontFamily="sans-serif" - android:textSize="14sp" - android:textColor="#EEEEEE" - android:lineSpacingMultiplier="1.46286" - android:text="@string/pip_onboarding_description" - android:alpha="0" /> - <Button - android:id="@+id/button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:layout_marginStart="408dp" - android:layout_below="@id/description" - android:layout_alignParentStart="true" - android:gravity="center" - android:paddingTop="10dp" - android:paddingBottom="10dp" - android:paddingStart="24dp" - android:paddingEnd="24dp" - android:fontFamily="sans-serif-condensed" - android:textSize="16sp" - android:textColor="#FFFFFF" - android:textAllCaps="true" - android:text="@string/pip_onboarding_button" - android:alpha="0" - android:background="#009688" - android:elevation="4dp" /> -</RelativeLayout> diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml deleted file mode 100644 index 608680cdf25f..000000000000 --- a/packages/SystemUI/res/layout/tv_pip_overlay.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -** -** Copyright 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. -*/ ---> - -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@drawable/tv_pip_overlay_background"> - - <TextView - android:id="@+id/guide_overlay" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_alignParentBottom="true" - android:paddingTop="6dp" - android:paddingBottom="6dp" - android:paddingStart="10dp" - android:paddingEnd="10dp" - android:textSize="14sp" - android:textColor="#EEEEEE" - android:fontFamily="sans-serif" - android:background="@drawable/tv_pip_overlay_text_background" - android:lineSpacingMultiplier="1.465" - android:gravity="center" - android:maxLines="2" - android:text="@string/pip_hold_home" /> -</RelativeLayout> diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml index 3817da017426..6e56d4a38d0c 100644 --- a/packages/SystemUI/res/values/colors_tv.xml +++ b/packages/SystemUI/res/values/colors_tv.xml @@ -21,4 +21,4 @@ <color name="recents_tv_card_title_text_color">#CCEEEEEE</color> <color name="recents_tv_dismiss_text_color">#7FEEEEEE</color> <color name="recents_tv_text_shadow_color">#7F000000</color> -</resources>
\ No newline at end of file +</resources> diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml deleted file mode 100644 index 09547dad0705..000000000000 --- a/packages/SystemUI/res/values/integers_tv.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<resources> - <!-- Delay of the onboarding animation start after it launches --> - <integer name="tv_pip_onboarding_anim_start_delay">1000</integer> - <!-- Duration of the onboarding animation duration --> - <integer name="tv_pip_onboarding_anim_duration">1000</integer> -</resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index eeb28c825ffa..33b1dd40e471 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1466,6 +1466,15 @@ <item quantity="other"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g>, and <xliff:g id="number">%3$d</xliff:g> others</item> </plurals> + <!-- Notification: Control panel: Accessibility description for expanded inline controls view, used + to control settings about notifications related to the current notification. --> + <string name="notification_channel_controls_opened_accessibility">Notification controls for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> opened</string> + <!-- Notification: Control panel: Accessibility description for announcing the closing of the + inline controls view. --> + <string name="notification_channel_controls_closed_accessibility">Notification controls for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> closed</string> + <!-- Notification: Control panel: Accessibility description for switch that is used to enable + or disable notifications from this channel --> + <string name="notification_channel_switch_accessibility">Allow notifications from this channel</string> <!-- Notification: Control panel: Label for button that launches notification settings. Used when this app has defined more than a single channel for notifications. --> <string name="notification_all_categories">All Categories</string> diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml index fb9e1f25f4dd..41626fcb0a49 100644 --- a/packages/SystemUI/res/values/strings_tv.xml +++ b/packages/SystemUI/res/values/strings_tv.xml @@ -27,14 +27,4 @@ <string name="pip_play">Play</string> <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] --> <string name="pip_pause">Pause</string> - <!-- Overlay text on picture-in-picture (PIP) to indicate that longpress HOME key to control PIP [CHAR LIMIT=52] --> - <string name="pip_hold_home">Hold <b>HOME</b> to control PIP</string> - <!-- Picture-in-Picture (PIP) onboarding screen --> - <eat-comment /> - <!-- Title for picture-in-picture (PIP) onboarding screen to indicate that an user is in PIP mode. [CHAR LIMIT=NONE] --> - <string name="pip_onboarding_title">Picture-in-picture</string> - <!-- Description for picture-in-picture (PIP) onboarding screen to indicate that longpress HOME key to control PIP. [CHAR LIMIT=NONE] --> - <string name="pip_onboarding_description">This keeps your video in view until you play another one. Press and hold <b>HOME</b> to control it.</string> - <!-- Button to close picture-in-picture (PIP) onboarding screen. --> - <string name="pip_onboarding_button">Got it</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index c9479b8b41f7..e5f04c6186b8 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -299,13 +299,13 @@ <style name="TextAppearance.Volume"> <item name="android:textStyle">normal</item> - <item name="android:textColor">#ffffffff</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:fontFamily">sans-serif</item> </style> <style name="TextAppearance.Volume.Header"> <item name="android:textSize">12sp</item> - <item name="android:textColor">@color/volume_slider_inactive</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="TextAppearance.Volume.ZenSummary"> @@ -316,7 +316,7 @@ <style name="TextAppearance.Volume.ZenDetail"> <item name="android:textSize">14sp</item> <item name="android:fontFamily">sans-serif</item> - <item name="android:textColor">@*android:color/quaternary_device_default_settings</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> </style> <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless"> 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/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index b447979be45d..616e5b9830ed 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -15,6 +15,7 @@ */ package com.android.keyguard; +import android.R.style; import android.app.Activity; import android.app.AlertDialog; import android.app.admin.DevicePolicyManager; @@ -23,6 +24,7 @@ import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.util.Slog; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; @@ -73,7 +75,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); + super(new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault), attrs, + defStyle); mSecurityModel = new KeyguardSecurityModel(context); mLockPatternUtils = new LockPatternUtils(context); mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); 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/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index e1aaaa36d77a..1e9cbdc45425 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -41,7 +41,6 @@ public final class Prefs { Key.DND_FAVORITE_BUCKET_INDEX, Key.DND_NONE_SELECTED, Key.DND_FAVORITE_ZEN, - Key.TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, Key.QS_HOTSPOT_ADDED, Key.QS_DATA_SAVER_ADDED, Key.QS_DATA_SAVER_DIALOG_SHOWN, @@ -62,7 +61,6 @@ public final class Prefs { String DND_FAVORITE_BUCKET_INDEX = "DndCountdownMinuteIndex"; String DND_NONE_SELECTED = "DndNoneSelected"; String DND_FAVORITE_ZEN = "DndFavoriteZen"; - String TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN = "TvPictureInPictureOnboardingShown"; String QS_HOTSPOT_ADDED = "QsHotspotAdded"; String QS_DATA_SAVER_ADDED = "QsDataSaverAdded"; String QS_DATA_SAVER_DIALOG_SHOWN = "QsDataSaverDialogShown"; 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/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 870d4d1c6a9d..90e1c0723945 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -145,6 +145,11 @@ public class DozeLog { log("screenOff why=" + why); } + public static void traceMissedTick(String delay) { + if (!ENABLED) return; + log("missedTick by=" + delay); + } + public static void traceKeyguard(boolean showing) { if (!ENABLED) return; log("keyguard " + showing); 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..03076cc4b7a8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -20,6 +20,8 @@ import android.app.AlarmManager; import android.content.Context; import android.os.Handler; import android.os.SystemClock; +import android.text.format.Formatter; +import android.util.Log; import com.android.systemui.util.wakelock.WakeLock; @@ -31,6 +33,7 @@ import java.util.GregorianCalendar; */ public class DozeUi implements DozeMachine.Part { + private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min private final Context mContext; private final AlarmManager mAlarmManager; private final DozeHost mHost; @@ -40,6 +43,7 @@ public class DozeUi implements DozeMachine.Part { private final AlarmManager.OnAlarmListener mTimeTick; private boolean mTimeTickScheduled = false; + private long mLastTimeTickElapsed = 0; public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine, WakeLock wakeLock, DozeHost host, Handler handler) { @@ -75,11 +79,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; @@ -100,15 +107,26 @@ public class DozeUi implements DozeMachine.Part { SystemClock.elapsedRealtime() + delta, "doze_time_tick", mTimeTick, mHandler); mTimeTickScheduled = true; + mLastTimeTickElapsed = SystemClock.elapsedRealtime(); } private void unscheduleTimeTick() { if (!mTimeTickScheduled) { return; } + verifyLastTimeTick(); mAlarmManager.cancel(mTimeTick); } + private void verifyLastTimeTick() { + long millisSinceLastTick = SystemClock.elapsedRealtime() - mLastTimeTickElapsed; + if (millisSinceLastTick > TIME_TICK_DEADLINE_MILLIS) { + String delay = Formatter.formatShortElapsedTime(mContext, millisSinceLastTick); + DozeLog.traceMissedTick(delay); + Log.e(DozeMachine.TAG, "Missed AOD time tick by " + delay); + } + } + private long roundToNextMinute(long timeInMillis) { Calendar calendar = GregorianCalendar.getInstance(); calendar.setTimeInMillis(timeInMillis); @@ -124,6 +142,7 @@ public class DozeUi implements DozeMachine.Part { // Alarm was canceled, but we still got the callback. Ignore. return; } + verifyLastTimeTick(); mHost.dozeTimeTick(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index c5653733bac7..28bd23ce9825 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -143,10 +143,10 @@ public class PipManager implements BasePipManager { @Override public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustement) { + Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) { mHandler.post(() -> { mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, animatingBounds, - fromImeAdjustement); + fromImeAdjustement, displayRotation); }); } 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..982b8085b216 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 @@ -220,6 +221,13 @@ public class PipMenuActivity extends Activity { } @Override + protected void onStop() { + super.onStop(); + + cancelDelayedFinish(); + } + + @Override protected void onDestroy() { super.onDestroy(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index fb8574da8e81..67255d35590a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -37,10 +37,12 @@ import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.util.Log; +import android.view.Choreographer; import android.view.animation.Interpolator; import com.android.internal.os.BackgroundThread; import com.android.internal.policy.PipSnapAlgorithm; +import com.android.internal.view.SurfaceFlingerVsyncChoreographer; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.statusbar.FlingAnimationUtils; @@ -72,6 +74,7 @@ public class PipMotionHelper { private Context mContext; private IActivityManager mActivityManager; + private SurfaceFlingerVsyncChoreographer mVsyncChoreographer; private Handler mHandler; private PipSnapAlgorithm mSnapAlgorithm; @@ -96,6 +99,8 @@ public class PipMotionHelper { mActivityManager = activityManager; mSnapAlgorithm = snapAlgorithm; mFlingAnimationUtils = flingAnimationUtils; + mVsyncChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, mContext.getDisplay(), + Choreographer.getInstance()); onConfigurationChanged(); } @@ -311,7 +316,8 @@ public class PipMotionHelper { * Animates the PiP from the expanded state to the normal state after the menu is hidden. */ void animateToUnexpandedState(Rect normalBounds, float savedSnapFraction, - Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized) { + Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized, + boolean immediate) { if (savedSnapFraction < 0f) { // If there are no saved snap fractions, then just use the current bounds savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), @@ -321,7 +327,11 @@ public class PipMotionHelper { if (minimized) { normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds); } - resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION); + if (immediate) { + movePip(normalBounds); + } else { + resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION); + } } /** @@ -394,7 +404,7 @@ public class PipMotionHelper { */ private void resizePipUnchecked(Rect toBounds) { if (!toBounds.equals(mBounds)) { - mHandler.post(() -> { + mVsyncChoreographer.scheduleAtSfVsync(() -> { try { mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */); mBounds.set(toBounds); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 3f26fddb1b3c..fbf7ff21b0ce 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -78,6 +78,7 @@ public class PipTouchHandler implements TunerService.Tunable { private final PipDismissViewController mDismissViewController; private final PipSnapAlgorithm mSnapAlgorithm; private final AccessibilityManager mAccessibilityManager; + private boolean mShowPipMenuOnAnimationEnd = false; // The current movement bounds private Rect mMovementBounds = new Rect(); @@ -89,6 +90,11 @@ public class PipTouchHandler implements TunerService.Tunable { private Rect mExpandedMovementBounds = new Rect(); private int mExpandedShortestEdgeSize; + // Used to workaround an issue where the WM rotation happens before we are notified, allowing + // us to send stale bounds + private int mDeferResizeToNormalBoundsUntilRotation = -1; + private int mDisplayRotation; + private Handler mHandler = new Handler(); private Runnable mShowDismissAffordance = new Runnable() { @Override @@ -216,13 +222,18 @@ public class PipTouchHandler implements TunerService.Tunable { setMinimizedStateInternal(false); } mDismissViewController.destroyDismissTarget(); - mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(), - mMovementBounds, true /* allowMenuTimeout */); + mShowPipMenuOnAnimationEnd = true; } public void onPinnedStackAnimationEnded() { // Always synchronize the motion helper bounds once PiP animations finish mMotionHelper.synchronizePinnedStackBounds(); + + if (mShowPipMenuOnAnimationEnd) { + mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(), + mMovementBounds, true /* allowMenuTimeout */); + mShowPipMenuOnAnimationEnd = false; + } } @Override @@ -250,7 +261,7 @@ public class PipTouchHandler implements TunerService.Tunable { } public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds, - boolean fromImeAdjustement) { + boolean fromImeAdjustement, int displayRotation) { // Re-calculate the expanded bounds mNormalBounds = normalBounds; Rect normalMovementBounds = new Rect(); @@ -304,7 +315,17 @@ public class PipTouchHandler implements TunerService.Tunable { // above mNormalMovementBounds = normalMovementBounds; mExpandedMovementBounds = expandedMovementBounds; + mDisplayRotation = displayRotation; updateMovementBounds(mMenuState); + + // If we have a deferred resize, apply it now + if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) { + mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, + mNormalMovementBounds, mMovementBounds, mIsMinimized, + true /* immediate */); + mSavedSnapFraction = -1f; + mDeferResizeToNormalBoundsUntilRotation = -1; + } } private void onRegistrationChanged(boolean isRegistered) { @@ -474,11 +495,34 @@ public class PipTouchHandler implements TunerService.Tunable { // Try and restore the PiP to the closest edge, using the saved snap fraction // if possible if (resize) { - Rect normalBounds = new Rect(mNormalBounds); - mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, - mNormalMovementBounds, mMovementBounds, mIsMinimized); + // This is a very special case: when the menu is expanded and visible, navigating to + // another activity can trigger auto-enter PiP, and if the revealed activity has a + // forced rotation set, then the controller will get updated with the new rotation + // of the display. However, at the same time, SystemUI will try to hide the menu by + // creating an animation to the normal bounds which are now stale. In such a case + // we defer the animation to the normal bounds until after the next + // onMovementBoundsChanged() call to get the bounds in the new orientation + if (mDeferResizeToNormalBoundsUntilRotation == -1) { + try { + int displayRotation = mPinnedStackController.getDisplayRotation(); + if (mDisplayRotation != displayRotation) { + mDeferResizeToNormalBoundsUntilRotation = displayRotation; + } + } catch (RemoteException e) { + Log.e(TAG, "Could not get display rotation from controller"); + } + } + + if (mDeferResizeToNormalBoundsUntilRotation == -1) { + Rect normalBounds = new Rect(mNormalBounds); + mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, + mNormalMovementBounds, mMovementBounds, mIsMinimized, + false /* immediate */); + mSavedSnapFraction = -1f; + } + } else { + mSavedSnapFraction = -1f; } - mSavedSnapFraction = -1f; } mMenuState = menuState; updateMovementBounds(menuState); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index ad290c388cb0..657f08be8b52 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -56,16 +56,12 @@ import java.util.List; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.systemui.Prefs.Key.TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN; - /** * Manages the picture-in-picture (PIP) UI and states. */ public class PipManager implements BasePipManager { private static final String TAG = "PipManager"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final boolean DEBUG_FORCE_ONBOARDING = - SystemProperties.getBoolean("debug.tv.pip_force_onboarding", false); private static final String SETTINGS_PACKAGE_AND_CLASS_DELIMITER = "/"; private static PipManager sPipManager; @@ -76,10 +72,9 @@ public class PipManager implements BasePipManager { */ public static final int STATE_NO_PIP = 0; /** - * State when PIP is shown with an overlay message on top of it. - * This is used as default PIP state. + * State when PIP is shown. This is used as default PIP state. */ - public static final int STATE_PIP_OVERLAY = 1; + public static final int STATE_PIP = 1; /** * State when PIP menu dialog is shown. */ @@ -126,7 +121,6 @@ public class PipManager implements BasePipManager { private int mPipTaskId = TASK_ID_NO_PIP; private ComponentName mPipComponentName; private MediaController mPipMediaController; - private boolean mOnboardingShown; private String[] mLastPackagesResourceGranted; private final PinnedStackListener mPinnedStackListener = new PinnedStackListener(); @@ -184,7 +178,7 @@ public class PipManager implements BasePipManager { @Override public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, - Rect animatingBounds, boolean fromImeAdjustement) { + Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) { mHandler.post(() -> { mDefaultPipBounds.set(normalBounds); }); @@ -212,8 +206,6 @@ public class PipManager implements BasePipManager { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED); mContext.registerReceiver(mBroadcastReceiver, intentFilter); - mOnboardingShown = Prefs.getBoolean( - mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false); if (sSettingsPackageAndClassNamePairList == null) { String[] settings = mContext.getResources().getStringArray( @@ -267,7 +259,7 @@ public class PipManager implements BasePipManager { // 1. Configuration changed due to the language change (RTL <-> RTL) // 2. SystemUI restarts after the crash mPipBounds = isSettingsShown() ? mSettingsPipBounds : mDefaultPipBounds; - resizePinnedStack(getPinnedStackInfo() == null ? STATE_NO_PIP : STATE_PIP_OVERLAY); + resizePinnedStack(getPinnedStackInfo() == null ? STATE_NO_PIP : STATE_PIP); } /** @@ -281,7 +273,7 @@ public class PipManager implements BasePipManager { * Shows the picture-in-picture menu if an activity is in picture-in-picture mode. */ public void showPictureInPictureMenu() { - if (mState == STATE_PIP_OVERLAY) { + if (mState == STATE_PIP) { resizePinnedStack(STATE_PIP_MENU); } } @@ -325,16 +317,6 @@ public class PipManager implements BasePipManager { } /** - * Shows PIP overlay UI by launching {@link PipOverlayActivity}. It also locates the pinned - * stack to the default PIP bound {@link com.android.internal.R.string - * .config_defaultPictureInPictureBounds}. - */ - private void showPipOverlay() { - if (DEBUG) Log.d(TAG, "showPipOverlay()"); - PipOverlayActivity.showPipOverlay(mContext); - } - - /** * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called * @param reason The reason for suspending resizing operations on the Pip. */ @@ -388,7 +370,7 @@ public class PipManager implements BasePipManager { case STATE_PIP_MENU: mCurrentPipBounds = mMenuModePipBounds; break; - case STATE_PIP_OVERLAY: + case STATE_PIP: mCurrentPipBounds = mPipBounds; break; default: @@ -454,17 +436,6 @@ public class PipManager implements BasePipManager { mMediaListeners.remove(listener); } - private void launchPipOnboardingActivityIfNeeded() { - if (DEBUG_FORCE_ONBOARDING || !mOnboardingShown) { - mOnboardingShown = true; - Prefs.putBoolean(mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, true); - - Intent intent = new Intent(mContext, PipOnboardingActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - } - } - /** * Returns {@code true} if PIP is shown. */ @@ -617,11 +588,11 @@ public class PipManager implements BasePipManager { return; } } - if (mState == STATE_PIP_OVERLAY) { + if (mState == STATE_PIP) { Rect bounds = isSettingsShown() ? mSettingsPipBounds : mDefaultPipBounds; if (mPipBounds != bounds) { mPipBounds = bounds; - resizePinnedStack(STATE_PIP_OVERLAY); + resizePinnedStack(STATE_PIP); } } } @@ -641,10 +612,9 @@ public class PipManager implements BasePipManager { mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1]; mPipComponentName = ComponentName.unflattenFromString( stackInfo.taskNames[stackInfo.taskNames.length - 1]); - // Set state to overlay so we show it when the pinned stack animation ends. - mState = STATE_PIP_OVERLAY; + // Set state to STATE_PIP so we show it when the pinned stack animation ends. + mState = STATE_PIP; mCurrentPipBounds = mPipBounds; - launchPipOnboardingActivityIfNeeded(); mMediaSessionManager.addOnActiveSessionsChangedListener( mActiveMediaSessionListener, null); updateMediaController(mMediaSessionManager.getActiveSessions(null)); @@ -671,9 +641,6 @@ public class PipManager implements BasePipManager { return; } switch (mState) { - case STATE_PIP_OVERLAY: - showPipOverlay(); - break; case STATE_PIP_MENU: showPipMenu(); break; diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java index 9945079445a8..ce1bea19ef60 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java @@ -56,7 +56,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { private void restorePipAndFinish() { if (mRestorePipSizeWhenClose) { // When PIP menu activity is closed, restore to the default position. - mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY); + mPipManager.resizePinnedStack(PipManager.STATE_PIP); } finish(); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipOnboardingActivity.java deleted file mode 100644 index 423530a70c04..000000000000 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipOnboardingActivity.java +++ /dev/null @@ -1,131 +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. - */ - -package com.android.systemui.pip.tv; - -import android.animation.Animator; -import android.animation.AnimatorInflater; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.app.Activity; -import android.graphics.drawable.AnimationDrawable; -import android.os.Bundle; -import android.view.View; -import android.view.KeyEvent; -import android.widget.ImageView; - -import com.android.systemui.R; - -/** - * Activity to show an overlay on top of PIP activity to show how to pop up PIP menu. - */ -public class PipOnboardingActivity extends Activity implements PipManager.Listener { - private final PipManager mPipManager = PipManager.getInstance(); - private AnimatorSet mEnterAnimator; - - @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - setContentView(R.layout.tv_pip_onboarding); - findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - mPipManager.addListener(this); - } - - @Override - public void onResume() { - super.onResume(); - mEnterAnimator = new AnimatorSet(); - mEnterAnimator.playTogether( - loadAnimator(R.id.background, R.anim.tv_pip_onboarding_background_enter_animation), - loadAnimator(R.id.remote, R.anim.tv_pip_onboarding_image_enter_animation), - loadAnimator(R.id.remote_button, R.anim.tv_pip_onboarding_image_enter_animation), - loadAnimator(R.id.title, R.anim.tv_pip_onboarding_title_enter_animation), - loadAnimator(R.id.description, - R.anim.tv_pip_onboarding_description_enter_animation), - loadAnimator(R.id.button, R.anim.tv_pip_onboarding_button_enter_animation)); - mEnterAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - ImageView button = findViewById(R.id.remote_button); - ((AnimationDrawable) button.getDrawable()).start(); - } - }); - int delay = getResources().getInteger(R.integer.tv_pip_onboarding_anim_start_delay); - mEnterAnimator.setStartDelay(delay); - mEnterAnimator.start(); - } - - private Animator loadAnimator(int viewResId, int animResId) { - Animator animator = AnimatorInflater.loadAnimator(this, animResId); - animator.setTarget(findViewById(viewResId)); - return animator; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (mEnterAnimator.isStarted()) { - return true; - } - return super.onKeyUp(keyCode, event); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (mEnterAnimator.isStarted()) { - return true; - } - return super.onKeyDown(keyCode, event); - } - - @Override - public void onPause() { - super.onPause(); - finish(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mPipManager.removeListener(this); - } - - @Override - public void onPipEntered() { } - - @Override - public void onPipActivityClosed() { - finish(); - } - - @Override - public void onShowPipMenu() { - finish(); - } - - @Override - public void onMoveToFullscreen() { - finish(); - } - - @Override - public void onPipResizeAboutToStart() { } -} diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipOverlayActivity.java deleted file mode 100644 index f52121ff119f..000000000000 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipOverlayActivity.java +++ /dev/null @@ -1,138 +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. - */ - -package com.android.systemui.pip.tv; - -import android.animation.Animator; -import android.animation.AnimatorInflater; -import android.app.Activity; -import android.app.ActivityOptions; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.view.View; -import android.widget.ImageView; - -import com.android.systemui.R; - -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; - -/** - * Activity to show an overlay on top of PIP activity to show how to pop up PIP menu. - */ -public class PipOverlayActivity extends Activity implements PipManager.Listener { - private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000; - - /** - * A flag to ensure the single instance of PipOverlayActivity to prevent it from restarting. - * Note that {@link PipManager} moves the PIPed activity to fullscreen if the activity is - * restarted. It's because the activity may be started by the Launcher or an intent again, - * but we don't want do so for the PipOverlayActivity. - */ - private static boolean sActivityCreated; - - private final PipManager mPipManager = PipManager.getInstance(); - private final Handler mHandler = new Handler(); - private View mGuideOverlayView; - private View mGuideButtonsView; - private ImageView mGuideButtonPlayPauseImageView; - private final Runnable mHideGuideOverlayRunnable = new Runnable() { - public void run() { - mFadeOutAnimation.start(); - } - }; - private Animator mFadeInAnimation; - private Animator mFadeOutAnimation; - - /** - * Shows PIP overlay UI only if it's not there. - */ - static void showPipOverlay(Context context) { - if (!sActivityCreated) { - Intent intent = new Intent(context, PipOverlayActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchStackId(PINNED_STACK_ID); - context.startActivity(intent, options.toBundle()); - } - } - - @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - sActivityCreated = true; - setContentView(R.layout.tv_pip_overlay); - mGuideOverlayView = findViewById(R.id.guide_overlay); - mPipManager.addListener(this); - mFadeInAnimation = AnimatorInflater.loadAnimator( - this, R.anim.tv_pip_overlay_fade_in_animation); - mFadeInAnimation.setTarget(mGuideOverlayView); - mFadeOutAnimation = AnimatorInflater.loadAnimator( - this, R.anim.tv_pip_overlay_fade_out_animation); - mFadeOutAnimation.setTarget(mGuideOverlayView); - } - - @Override - protected void onResume() { - super.onResume(); - mFadeInAnimation.start(); - mHandler.removeCallbacks(mHideGuideOverlayRunnable); - mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS); - } - - @Override - protected void onStop() { - super.onStop(); - mHandler.removeCallbacks(mHideGuideOverlayRunnable); - finish(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - sActivityCreated = false; - mHandler.removeCallbacksAndMessages(null); - mPipManager.removeListener(this); - mPipManager.resumePipResizing( - PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH); - } - - @Override - public void onPipEntered() { } - - @Override - public void onPipActivityClosed() { - finish(); - } - - @Override - public void onShowPipMenu() { - finish(); - } - - @Override - public void onMoveToFullscreen() { - finish(); - } - - @Override - public void onPipResizeAboutToStart() { - finish(); - mPipManager.suspendPipResizing( - PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index d51fe8a2f690..53c36e69ef7e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java @@ -167,6 +167,9 @@ public class QSFooter extends LinearLayout implements if (mAlarmShowing) { builder.addFloat(mDate, "alpha", 1, 0) .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth()); + } else { + mDate.setAlpha(1); + mDateTimeGroup.setTranslationX(0); } mAnimator = builder.build(); setExpansion(mExpansionAmount); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 7518527a3093..e457d7247434 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -77,6 +77,9 @@ public class QuickStatusBarHeader extends RelativeLayout { BatteryMeterView battery = findViewById(R.id.battery); battery.setForceShowPercent(true); + // Don't show the Wi-Fi indicator here, because it is shown just below in the tile. + SignalClusterView signalCluster = findViewById(R.id.signal_cluster); + signalCluster.setForceBlockWifi(); mActivityStarter = Dependency.get(ActivityStarter.class); } 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 92ff17a1f029..d74e3ac656f7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -128,7 +128,7 @@ public class CellularTile extends QSTileImpl<SignalState> { state.value = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); state.icon = ResourceIcon.get(R.drawable.ic_data_unavailable); - state.state = cb.airplaneModeEnabled || !cb.enabled ? Tile.STATE_UNAVAILABLE + state.state = cb.airplaneModeEnabled || !cb.enabled || cb.noSim ? Tile.STATE_UNAVAILABLE : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; if (state.state == Tile.STATE_ACTIVE) { state.icon = ResourceIcon.get(R.drawable.ic_data_on); @@ -161,44 +161,27 @@ public class CellularTile extends QSTileImpl<SignalState> { private static final class CallbackInfo { boolean enabled; - boolean wifiEnabled; boolean airplaneModeEnabled; - String signalContentDescription; - int dataTypeIconId; - String dataContentDescription; boolean activityIn; boolean activityOut; - String enabledDesc; boolean noSim; - boolean isDataTypeIconWide; boolean roaming; } private final class CellSignalCallback implements SignalCallback { private final CallbackInfo mInfo = new CallbackInfo(); - @Override - public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, - boolean activityIn, boolean activityOut, String description, boolean isTransient) { - mInfo.wifiEnabled = enabled; - refreshState(mInfo); - } @Override - public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, - int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, - String description, boolean isWide, int subId, boolean roaming) { - if (qsIcon == null) { + public void setMobileDataIndicators(IconState statusIcon, int statusType, + boolean activityIn, boolean activityOut, String typeContentDescription, + int subId, boolean roaming, boolean isEmergency) { + if (statusIcon == null) { // Not data sim, don't display. return; } - mInfo.enabled = qsIcon.visible; - mInfo.signalContentDescription = qsIcon.contentDescription; - mInfo.dataTypeIconId = qsType; - mInfo.dataContentDescription = typeContentDescription; + mInfo.enabled = statusIcon.visible; mInfo.activityIn = activityIn; mInfo.activityOut = activityOut; - mInfo.enabledDesc = description; - mInfo.isDataTypeIconWide = qsType != 0 && isWide; mInfo.roaming = roaming; refreshState(mInfo); } @@ -206,15 +189,6 @@ public class CellularTile extends QSTileImpl<SignalState> { @Override public void setNoSims(boolean show) { mInfo.noSim = show; - if (mInfo.noSim) { - // Make sure signal gets cleared out when no sims. - mInfo.dataTypeIconId = 0; - // Show a No SIMs description to avoid emergency calls message. - mInfo.enabled = true; - mInfo.enabledDesc = mContext.getString( - R.string.keyguard_missing_sim_message_short); - mInfo.signalContentDescription = mInfo.enabledDesc; - } refreshState(mInfo); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 397b78dbd281..ccebd7ceec32 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -82,7 +82,6 @@ import com.android.internal.os.BackgroundThread; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.R; import com.android.systemui.pip.tv.PipMenuActivity; -import com.android.systemui.pip.tv.PipOnboardingActivity; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.RecentsImpl; @@ -113,7 +112,6 @@ public class SystemServicesProxy { final static List<String> sRecentsBlacklist; static { sRecentsBlacklist = new ArrayList<>(); - sRecentsBlacklist.add(PipOnboardingActivity.class.getName()); sRecentsBlacklist.add(PipMenuActivity.class.getName()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 677642e53d6e..cc9175382903 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -1115,6 +1115,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mNotificationInflater.setInflateExceptionHandler(inflateExceptionHandler); } + public void setNeedsRedaction(boolean needsRedaction) { + mNotificationInflater.setRedactAmbient(needsRedaction); + } + public interface ExpansionLogger { public void logNotificationExpansion(String key, boolean userAction, boolean expanded); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 8f160dc0384e..609856522e75 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -428,6 +428,9 @@ public class NotificationContentView extends FrameLayout { mAmbientChild.animate().cancel(); removeView(mAmbientChild); } + if (child == null) { + return; + } addView(child); mAmbientChild = child; mAmbientWrapper = NotificationViewWrapper.wrap(getContext(), child, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java index 2713f58272d0..0a99ee6c781f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java @@ -39,6 +39,7 @@ import android.util.Log; import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -255,6 +256,7 @@ public class NotificationGuts extends FrameLayout { } public void setExposed(boolean exposed, boolean needsFalsingProtection) { + final boolean wasExposed = mExposed; mExposed = exposed; mNeedsFalsingProtection = needsFalsingProtection; if (mExposed && mNeedsFalsingProtection) { @@ -262,6 +264,13 @@ public class NotificationGuts extends FrameLayout { } else { mHandler.removeCallbacks(mFalsingCheck); } + if (wasExposed != mExposed && mGutsContent != null) { + final View contentView = mGutsContent.getContentView(); + contentView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + if (mExposed) { + contentView.requestAccessibilityFocus(); + } + } } public boolean willBeRemoved() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java index 7928575df4d4..89251897e25f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java @@ -35,6 +35,7 @@ import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; +import android.view.accessibility.AccessibilityEvent; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Switch; @@ -57,6 +58,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private INotificationManager mINotificationManager; private String mPkg; + private String mAppName; private int mAppUid; private List<NotificationChannel> mNotificationChannels; private NotificationChannel mSingleNotificationChannel; @@ -125,7 +127,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - String appName = mPkg; + mAppName = mPkg; Drawable pkgicon = null; CharSequence channelNameText = ""; ApplicationInfo info = null; @@ -137,7 +139,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G | PackageManager.MATCH_DIRECT_BOOT_AWARE); if (info != null) { mAppUid = info.uid; - appName = String.valueOf(pm.getApplicationLabel(info)); + mAppName = String.valueOf(pm.getApplicationLabel(info)); pkgicon = pm.getApplicationIcon(info); } } catch (PackageManager.NameNotFoundException e) { @@ -189,7 +191,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } else { channelNameText = mSingleNotificationChannel.getName(); } - ((TextView) findViewById(R.id.pkgname)).setText(appName); + ((TextView) findViewById(R.id.pkgname)).setText(mAppName); ((TextView) findViewById(R.id.channel_name)).setText(channelNameText); // Set group information if this channel has an associated group. @@ -309,6 +311,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G }); } + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + if (mGutsContainer != null && + event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + if (mGutsContainer.isExposed()) { + event.getText().add(mContext.getString( + R.string.notification_channel_controls_opened_accessibility, mAppName)); + } else { + event.getText().add(mContext.getString( + R.string.notification_channel_controls_closed_accessibility, mAppName)); + } + } + } + private void updateSecondaryText() { final boolean disabled = mSingleNotificationChannel != null && getSelectedImportance() == IMPORTANCE_NONE; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java index fee24b7b7645..802925a315eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java @@ -227,6 +227,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl if (mShouldShowMenu && !NotificationStackScrollLayout.isPinnedHeadsUp(view) && !mParent.areGutsExposed() + && !mParent.isDark() && (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag))) { // Only show the menu if we're not a heads up view and guts aren't exposed. mCheckForDrag = new CheckForDrag(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index dc254f9fdc1e..b01d9cc07bf5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -24,8 +24,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Rect; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.telephony.SubscriptionInfo; @@ -120,6 +118,7 @@ public class SignalClusterView extends LinearLayout implements NetworkController private boolean mBlockWifi; private boolean mBlockEthernet; private boolean mActivityEnabled; + private boolean mForceBlockWifi; public SignalClusterView(Context context) { this(context, null); @@ -151,6 +150,16 @@ public class SignalClusterView extends LinearLayout implements NetworkController updateActivityEnabled(); } + public void setForceBlockWifi() { + mForceBlockWifi = true; + mBlockWifi = true; + if (isAttachedToWindow()) { + // Re-register to get new callbacks. + mNetworkController.removeCallback(this); + mNetworkController.addCallback(this); + } + } + @Override public void onTuningChanged(String key, String newValue) { if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) { @@ -167,7 +176,7 @@ public class SignalClusterView extends LinearLayout implements NetworkController mBlockAirplane = blockAirplane; mBlockMobile = blockMobile; mBlockEthernet = blockEthernet; - mBlockWifi = blockWifi; + mBlockWifi = blockWifi || mForceBlockWifi; // Re-register to get new callbacks. mNetworkController.removeCallback(this); mNetworkController.addCallback(this); @@ -288,9 +297,9 @@ public class SignalClusterView extends LinearLayout implements NetworkController } @Override - public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, - int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, - String description, boolean isWide, int subId, boolean roaming) { + public void setMobileDataIndicators(IconState statusIcon, int statusType, + boolean activityIn, boolean activityOut, String typeContentDescription, + int subId, boolean roaming, boolean isEmergency) { PhoneState state = getState(subId); if (state == null) { return; @@ -300,7 +309,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController state.mMobileTypeId = statusType; state.mMobileDescription = statusIcon.contentDescription; state.mMobileTypeDescription = typeContentDescription; - state.mIsMobileTypeIconWide = statusType != 0 && isWide; state.mRoaming = roaming; state.mActivityIn = activityIn && mActivityEnabled; state.mActivityOut = activityOut && mActivityEnabled; @@ -525,7 +533,7 @@ public class SignalClusterView extends LinearLayout implements NetworkController mWifiAirplaneSpacer.setVisibility(View.GONE); } - if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) { + if (((anyMobileVisible && firstMobileTypeId == 0) || mNoSimsVisible) && mWifiVisible) { mWifiSignalSpacer.setVisibility(View.VISIBLE); } else { mWifiSignalSpacer.setVisibility(View.GONE); @@ -636,7 +644,6 @@ public class SignalClusterView extends LinearLayout implements NetworkController private int mMobileStrengthId = 0, mMobileTypeId = 0; private int mLastMobileStrengthId = -1; private int mLastMobileTypeId = -1; - private boolean mIsMobileTypeIconWide; private String mMobileDescription, mMobileTypeDescription; private ViewGroup mMobileGroup; @@ -692,12 +699,8 @@ public class SignalClusterView extends LinearLayout implements NetworkController // When this isn't next to wifi, give it some extra padding between the signals. mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0, 0, 0, 0); - mMobile.setPaddingRelative( - mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding, - 0, 0, 0); - mMobileDark.setPaddingRelative( - mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding, - 0, 0, 0); + mMobile.setPaddingRelative(mMobileDataIconStartPadding, 0, 0, 0); + mMobileDark.setPaddingRelative(mMobileDataIconStartPadding, 0, 0, 0); if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d", (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 92bfae9e3f5c..ec15d10ac351 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -499,12 +499,18 @@ public class StatusBarIconView extends AnimatedImageView { } private void setColorInternal(int color) { - if (color != NO_COLOR) { - setImageTintList(ColorStateList.valueOf(color)); + mCurrentSetColor = color; + updateIconColor(); + } + + private void updateIconColor() { + if (mCurrentSetColor != NO_COLOR) { + setImageTintList(ColorStateList.valueOf(NotificationUtils.interpolateColors( + mCurrentSetColor, Color.WHITE, mDarkAmount))); } else { setImageTintList(null); + mDozer.updateGrayscale(this, mDarkAmount); } - mCurrentSetColor = color; } public void setIconColor(int iconColor, boolean animate) { @@ -669,10 +675,10 @@ public class StatusBarIconView extends AnimatedImageView { } public void setDark(boolean dark, boolean fade, long delay) { - mDozer.setImageDark(this, dark, fade, delay, mIconColor == NO_COLOR); mDozer.setIntensityDark(f -> { mDarkAmount = f; updateDecorColor(); + updateIconColor(); }, dark, fade, delay); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java index d592c5f5b7f3..0b3b3cb671e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java @@ -35,8 +35,7 @@ public class NotificationDozeHelper { startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - updateGrayscaleMatrix((float) animation.getAnimatedValue()); - target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix)); + updateGrayscale(target, (float) animation.getAnimatedValue()); } }, dark, delay, new AnimatorListenerAdapter() { @Override @@ -49,8 +48,12 @@ public class NotificationDozeHelper { } public void updateGrayscale(ImageView target, boolean dark) { - if (dark) { - updateGrayscaleMatrix(1f); + updateGrayscale(target, dark ? 1 : 0); + } + + public void updateGrayscale(ImageView target, float darkAmount) { + if (darkAmount > 0) { + updateGrayscaleMatrix(darkAmount); target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix)); } else { target.setColorFilter(null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java index 73eecbbf2728..2e34f2483a85 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java @@ -21,6 +21,8 @@ import android.content.Context; import android.service.notification.StatusBarNotification; import android.util.Log; import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; import android.widget.RemoteViews; import com.android.internal.annotations.VisibleForTesting; @@ -49,6 +51,7 @@ public class NotificationInflater { private RemoteViews.OnClickHandler mRemoteViewClickHandler; private boolean mIsChildInGroup; private InflationExceptionHandler mInflateExceptionHandler; + private boolean mRedactAmbient; public NotificationInflater(ExpandableNotificationRow row) { mRow = row; @@ -92,6 +95,21 @@ public class NotificationInflater { mRemoteViewClickHandler = remoteViewClickHandler; } + public void setRedactAmbient(boolean redactAmbient) { + if (mRedactAmbient != redactAmbient) { + mRedactAmbient = redactAmbient; + if (mRow.getEntry() == null) { + return; + } + try { + inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW); + } catch (InflationException e) { + mInflateExceptionHandler.handleInflationException( + mRow.getStatusBarNotification(), e); + } + } + } + public void inflateNotificationViews() throws InflationException { inflateNotificationViews(FLAG_REINFLATE_ALL); } @@ -123,6 +141,8 @@ public class NotificationInflater { Notification.Builder builder, Context packageContext) { NotificationData.Entry entry = mRow.getEntry(); NotificationContentView privateLayout = mRow.getPrivateLayout(); + NotificationContentView publicLayout = mRow.getPublicLayout(); + boolean isLowPriority = mIsLowPriority && !mIsChildInGroup; if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) { final RemoteViews newContentView = createContentView(builder, @@ -190,7 +210,6 @@ public class NotificationInflater { } if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) { - NotificationContentView publicLayout = mRow.getPublicLayout(); final RemoteViews newPublicNotification = builder.makePublicContentView(); if (!compareRemoteViews(newPublicNotification, entry.cachedPublicContentView)) { @@ -209,18 +228,24 @@ public class NotificationInflater { } if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) { - final RemoteViews newAmbientNotification - = builder.makeAmbientNotification(); - if (!compareRemoteViews(newAmbientNotification, entry.cachedAmbientContentView)) { + final RemoteViews newAmbientNotification = mRedactAmbient + ? builder.makePublicAmbientNotification() + : builder.makeAmbientNotification(); + NotificationContentView newParent = mRedactAmbient ? publicLayout : privateLayout; + NotificationContentView otherParent = !mRedactAmbient ? publicLayout : privateLayout; + + if (newParent.getAmbientChild() == null || + !compareRemoteViews(newAmbientNotification, entry.cachedAmbientContentView)) { View ambientContentView = newAmbientNotification.apply( packageContext, - privateLayout, + newParent, mRemoteViewClickHandler); ambientContentView.setIsRootNamespace(true); - privateLayout.setAmbientChild(ambientContentView); + newParent.setAmbientChild(ambientContentView); + otherParent.setAmbientChild(null); } else { newAmbientNotification.reapply(packageContext, - privateLayout.getAmbientChild(), + newParent.getAmbientChild(), mRemoteViewClickHandler); } entry.cachedAmbientContentView = newAmbientNotification; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java index be162667751b..dd997493bb09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java @@ -23,6 +23,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewStub; import android.widget.LinearLayout; import com.android.systemui.Dependency; @@ -36,6 +37,7 @@ import com.android.systemui.statusbar.policy.DarkIconDispatcher; import com.android.systemui.statusbar.policy.EncryptionHelper; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; /** * Contains the collapsed status bar and handles hiding/showing based on disable flags @@ -56,6 +58,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private DarkIconManager mDarkIconManager; private SignalClusterView mSignalClusterView; + private SignalCallback mSignalCallback = new SignalCallback() { + @Override + public void setIsAirplaneMode(NetworkController.IconState icon) { + mStatusBarComponent.recomputeDisableFlags(true /* animate */); + } + }; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -84,6 +93,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSignalClusterView); // Default to showing until we know otherwise. showSystemIconArea(false); + initEmergencyCryptkeeperText(); } @Override @@ -109,6 +119,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue super.onDestroyView(); Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSignalClusterView); Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager); + if (mNetworkController.hasEmergencyCryptKeeperText()) { + mNetworkController.removeCallback(mSignalCallback); + } } public void initNotificationIconArea(NotificationIconAreaController @@ -233,4 +246,17 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue .start(); } } + + private void initEmergencyCryptkeeperText() { + View emergencyViewStub = mStatusBar.findViewById(R.id.emergency_cryptkeeper_text); + if (mNetworkController.hasEmergencyCryptKeeperText()) { + if (emergencyViewStub != null) { + ((ViewStub) emergencyViewStub).inflate(); + } + mNetworkController.addCallback(mSignalCallback); + } else if (emergencyViewStub != null) { + ViewGroup parent = (ViewGroup) emergencyViewStub.getParent(); + parent.removeView(emergencyViewStub); + } + } } 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/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index dadb749af2d0..67d5b6a2959e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -57,6 +57,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target; private static final int TAG_START_ALPHA = R.id.scrim_alpha_start; private static final int TAG_END_ALPHA = R.id.scrim_alpha_end; + private static final float NOT_INITIALIZED = -1; private final LightBarController mLightBarController; protected final ScrimView mScrimBehind; @@ -87,9 +88,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private boolean mDozing; private float mDozeInFrontAlpha; private float mDozeBehindAlpha; - private float mCurrentInFrontAlpha; - private float mCurrentBehindAlpha; - private float mCurrentHeadsUpAlpha = 1; + private float mCurrentInFrontAlpha = NOT_INITIALIZED; + private float mCurrentBehindAlpha = NOT_INITIALIZED; + private float mCurrentHeadsUpAlpha = NOT_INITIALIZED; private int mPinnedHeadsUpCount; private float mTopHeadsUpDragAmount; private View mDraggedHeadsUpView; @@ -111,6 +112,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mScrimBehindAlpha = context.getResources().getFloat(R.dimen.scrim_behind_alpha); updateHeadsUpScrim(false); + updateScrims(); } public void setKeyguardShowing(boolean showing) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java index a9eb20ba3a57..6361eb6ccb89 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java @@ -57,12 +57,12 @@ public class SignalDrawable extends Drawable { 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; + public static final int STATE_SHIFT = 16; + public static final int STATE_MASK = 0xff << STATE_SHIFT; + public static final int STATE_NONE = 0; + public static final int STATE_EMPTY = 1; + public static final int STATE_CUT = 2; + public static final int STATE_CARRIER_CHANGE = 3; private static final long DOT_DELAY = 1000; 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..79191f3c2114 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -31,6 +31,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCE import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; +import android.R.style; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; @@ -48,10 +49,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; -import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -95,6 +94,7 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; +import android.view.ContextThemeWrapper; import android.view.Display; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -139,7 +139,6 @@ import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.PluginFragmentListener; import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.pip.phone.PipManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; @@ -1114,14 +1113,11 @@ 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); - initEmergencyCryptkeeperText(); - mKeyguardBottomArea.setStatusBar(this); mKeyguardBottomArea.setUserSetupComplete(mUserSetup); if (UserManager.get(mContext).isUserSwitcherEnabled()) { @@ -1231,24 +1227,6 @@ public class StatusBar extends SystemUI implements DemoMode, }); } - private void initEmergencyCryptkeeperText() { - View emergencyViewStub = mStatusBarWindow.findViewById(R.id.emergency_cryptkeeper_text); - if (mNetworkController.hasEmergencyCryptKeeperText()) { - if (emergencyViewStub != null) { - ((ViewStub) emergencyViewStub).inflate(); - } - mNetworkController.addCallback(new NetworkController.SignalCallback() { - @Override - public void setIsAirplaneMode(NetworkController.IconState icon) { - recomputeDisableFlags(true /* animate */); - } - }); - } else if (emergencyViewStub != null) { - ViewGroup parent = (ViewGroup) emergencyViewStub.getParent(); - parent.removeView(emergencyViewStub); - } - } - /** * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the * background window of the status bar is clicked. @@ -1358,7 +1336,10 @@ public class StatusBar extends SystemUI implements DemoMode, } private void inflateDismissView() { - mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( + // Always inflate with a dark theme, since this sits on the scrim. + ContextThemeWrapper themedContext = new ContextThemeWrapper(mContext, + style.Theme_DeviceDefault); + mDismissView = (DismissView) LayoutInflater.from(themedContext).inflate( R.layout.status_bar_notification_dismiss_all, mStackScroller, false); mDismissView.setOnButtonClickListener(new View.OnClickListener() { @Override @@ -1830,6 +1811,7 @@ public class StatusBar extends SystemUI implements DemoMode, updatePublicContentView(ent, ent.notification); } ent.row.setSensitive(sensitive, deviceSensitive); + ent.row.setNeedsRedaction(needsRedaction(ent)); if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) { ExpandableNotificationRow summary = mGroupManager.getGroupSummary( ent.row.getStatusBarNotification()); @@ -1918,6 +1900,21 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationIconAreaController.updateNotificationIcons(mNotificationData); } + /** @return true if the entry needs redaction when on the lockscreen. */ + private boolean needsRedaction(Entry ent) { + int userId = ent.notification.getUserId(); + + boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId); + boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId); + boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction; + + boolean notificationRequestsRedaction = + ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE; + boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey()); + + return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen; + } + /** * Disable QS if device not provisioned. * If the user switcher is simple then disable QS during setup because @@ -1928,6 +1925,7 @@ public class StatusBar extends SystemUI implements DemoMode, && (mUserSetup || mUserSwitcherController == null || !mUserSwitcherController.isSimpleUserSwitcher()) && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0) + && !mDozing && !ONLY_CORE_APPS); } @@ -4332,6 +4330,8 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); mScrimController.setDozing(mDozing); mKeyguardIndicationController.setDozing(mDozing); + mNotificationPanel.setDark(mDozing); + updateQsExpansionEnabled(); // 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. @@ -5864,6 +5875,9 @@ public class StatusBar extends SystemUI implements DemoMode, } final ExpandableNotificationRow row = (ExpandableNotificationRow) v; + if (row.isDark()) { + return false; + } bindGuts(row, item); NotificationGuts guts = row.getGuts(); @@ -5911,8 +5925,10 @@ public class StatusBar extends SystemUI implements DemoMode, } }); a.start(); - guts.setExposed(true /* exposed */, - mState == StatusBarState.KEYGUARD /* needsFalsingProtection */); + final boolean needsFalsingProtection = + (mState == StatusBarState.KEYGUARD && + !mAccessibilityManager.isTouchExplorationEnabled()); + guts.setExposed(true /* exposed */, needsFalsingProtection); row.closeRemoteInput(); mStackScroller.onHeightChanged(row, true /* needsAnimation */); mNotificationGutsExposed = guts; @@ -6163,6 +6179,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } + row.setNeedsRedaction(needsRedaction(entry)); boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey()); row.setIsLowPriority(isLowPriority); // bind the click event to the content area @@ -6527,7 +6544,6 @@ public class StatusBar extends SystemUI implements DemoMode, NotificationData.Entry entry = new NotificationData.Entry(sbn); Dependency.get(LeakDetector.class).trackInstance(entry); entry.createIcons(mContext, sbn); - // Construct the expanded view. inflateViews(entry, mStackScroller); return entry; 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/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java index a456786d712f..e98dc987aa5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java @@ -110,30 +110,24 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa public void setWifiIndicators(final boolean enabled, final IconState statusIcon, final IconState qsIcon, final boolean activityIn, final boolean activityOut, final String description, boolean isTransient) { - post(new Runnable() { - @Override - public void run() { - for (SignalCallback callback : mSignalCallbacks) { - callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut, - description, isTransient); - } + post(() -> { + for (SignalCallback callback : mSignalCallbacks) { + callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut, + description, isTransient); } }); } @Override - public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon, - final int statusType, final int qsType,final boolean activityIn, + public void setMobileDataIndicators(final IconState statusIcon, + final int statusType, final boolean activityIn, final boolean activityOut, final String typeContentDescription, - final String description, final boolean isWide, final int subId, boolean roaming) { - post(new Runnable() { - @Override - public void run() { - for (SignalCallback signalCluster : mSignalCallbacks) { - signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType, - activityIn, activityOut, typeContentDescription, description, isWide, - subId, roaming); - } + final int subId, boolean roaming, boolean isEmergency) { + post(() -> { + for (SignalCallback signalCluster : mSignalCallbacks) { + signalCluster.setMobileDataIndicators(statusIcon, statusType, + activityIn, activityOut, typeContentDescription, + subId, roaming, isEmergency); } }); } 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 67b5596e34c9..4421a6ab0cfd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -244,7 +244,8 @@ public class MobileSignalController extends SignalController< return SignalDrawable.getCarrierChangeState(getNumLevels()); } else if (mCurrentState.connected) { return SignalDrawable.getState(mCurrentState.level, getNumLevels(), - mCurrentState.inetCondition == 0); + mCurrentState.inetCondition == 0 || + (mCurrentState.dataDisabled && mCurrentState.userSetup)); } else if (mCurrentState.enabled) { return SignalDrawable.getEmptyState(getNumLevels()); } else { @@ -263,24 +264,14 @@ public class MobileSignalController extends SignalController< String contentDescription = getStringIfExists(getContentDescription()); String dataContentDescription = getStringIfExists(icons.mDataContentDescription); - final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED + final boolean dataDisabled = mCurrentState.dataDisabled && mCurrentState.userSetup; // Show icon in QS when we are connected or data is disabled. - boolean showDataIcon = mCurrentState.dataConnected || dataDisabled; + boolean showDataIcon = mCurrentState.dataConnected; IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode, getCurrentIconId(), contentDescription); - int qsTypeIcon = 0; - IconState qsIcon = null; - String description = null; - // Only send data sim callbacks to QS. - if (mCurrentState.dataSim) { - qsTypeIcon = showDataIcon ? icons.mQsDataType : 0; - qsIcon = new IconState(mCurrentState.enabled - && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription); - description = mCurrentState.isEmergency ? null : mCurrentState.networkName; - } boolean activityIn = mCurrentState.dataConnected && !mCurrentState.carrierNetworkChangeMode && mCurrentState.activityIn; @@ -289,9 +280,10 @@ public class MobileSignalController extends SignalController< && mCurrentState.activityOut; showDataIcon &= mCurrentState.isDefault || dataDisabled; int typeIcon = showDataIcon ? icons.mDataType : 0; - callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon, - activityIn, activityOut, dataContentDescription, description, icons.mIsWide, - mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming); + callback.setMobileDataIndicators(statusIcon, typeIcon, + activityIn, activityOut, dataContentDescription, + mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming, + mCurrentState.isEmergency); } @Override @@ -438,14 +430,14 @@ public class MobileSignalController extends SignalController< } else { mCurrentState.iconGroup = mDefaultIcons; } + mCurrentState.dataDisabled = isDataDisabled(); mCurrentState.dataConnected = mCurrentState.connected - && mDataState == TelephonyManager.DATA_CONNECTED; + && mDataState == TelephonyManager.DATA_CONNECTED + && !mCurrentState.dataDisabled; mCurrentState.roaming = isRoaming(); if (isCarrierNetworkChangeActive()) { mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE; - } else if (isDataDisabled()) { - mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED; } if (isEmergencyOnly() != mCurrentState.isEmergency) { mCurrentState.isEmergency = isEmergencyOnly(); @@ -577,6 +569,7 @@ public class MobileSignalController extends SignalController< boolean isDefault; boolean userSetup; boolean roaming; + boolean dataDisabled; @Override public void copyFrom(State s) { @@ -592,6 +585,7 @@ public class MobileSignalController extends SignalController< carrierNetworkChangeMode = state.carrierNetworkChangeMode; userSetup = state.userSetup; roaming = state.roaming; + dataDisabled = state.dataDisabled; } @Override @@ -609,6 +603,7 @@ public class MobileSignalController extends SignalController< builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode) .append(','); builder.append("userSetup=").append(userSetup); + builder.append("dataDisabled=").append(dataDisabled); } @Override @@ -623,6 +618,7 @@ public class MobileSignalController extends SignalController< && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode && ((MobileState) o).userSetup == userSetup && ((MobileState) o).isDefault == isDefault + && ((MobileState) o).dataDisabled == dataDisabled && ((MobileState) o).roaming == roaming; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index c02ce0ea6335..ab4a8f21ba24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -48,9 +48,9 @@ public interface NetworkController extends CallbackController<SignalCallback>, D default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description, boolean isTransient) {} - default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, - int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, - String description, boolean isWide, int subId, boolean roaming) {} + default void setMobileDataIndicators(IconState statusIcon, int statusType, + boolean activityIn, boolean activityOut, String typeContentDescription, + int subId, boolean roaming, boolean isEmergency) {} default void setSubs(List<SubscriptionInfo> subs) {} default void setNoSims(boolean show) {} 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 c21f444d0bf3..60f4ab8ffe0e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -867,7 +867,6 @@ public class NetworkControllerImpl extends BroadcastReceiver datatype.equals("h") ? TelephonyIcons.H : datatype.equals("lte") ? TelephonyIcons.LTE : datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : - datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : TelephonyIcons.UNKNOWN; } if (args.containsKey("roam")) { 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 aaa0568a72cd..ec7e557fde81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -44,10 +44,6 @@ class TelephonyIcons { 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_DATA_DISABLED = R.drawable.stat_sys_data_disabled; - - static final int QS_ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled; - static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup( "CARRIER_NETWORK_CHANGE", null, @@ -221,20 +217,5 @@ class TelephonyIcons { true, TelephonyIcons.QS_DATA_LTE_PLUS ); - - static final MobileIconGroup DATA_DISABLED = new MobileIconGroup( - "DataDisabled", - null, - null, - AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, - 0, 0, - 0, - 0, - AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], - R.string.accessibility_cell_data_off, - TelephonyIcons.ICON_DATA_DISABLED, - false, - TelephonyIcons.QS_ICON_DATA_DISABLED - ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java index 374408d3ec7a..dfc3591678ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java @@ -47,6 +47,7 @@ public class WifiIcons { static final int QS_WIFI_NO_NETWORK = R.drawable.ic_qs_wifi_no_network; static final int WIFI_NO_NETWORK = R.drawable.stat_sys_wifi_signal_null; + static final int WIFI_DISCONNECTED = R.drawable.stat_sys_wifi_signal_disconnected; static final int WIFI_LEVEL_COUNT = WIFI_SIGNAL_STRENGTH[0].length; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 2104cb1421aa..a773acf317c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -80,7 +80,7 @@ public class WifiSignalController extends AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH, WifiIcons.WIFI_NO_NETWORK, WifiIcons.QS_WIFI_NO_NETWORK, - WifiIcons.WIFI_NO_NETWORK, + WifiIcons.WIFI_DISCONNECTED, WifiIcons.QS_WIFI_NO_NETWORK, AccessibilityContentDescriptions.WIFI_NO_CONNECTION ); @@ -133,8 +133,7 @@ public class WifiSignalController extends @Override public void notifyListeners(SignalCallback callback) { // only show wifi in the cluster if connected or if wifi-only - boolean wifiVisible = mCurrentState.enabled - && (mCurrentState.connected || !mHasMobileData); + boolean wifiVisible = true; String wifiDesc = wifiVisible ? mCurrentState.ssid : null; boolean ssidPresent = wifiVisible && mCurrentState.ssid != null; String contentDescription = getStringIfExists(getContentDescription()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java index 3ed1681644f2..f6c75a8f0b84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java @@ -114,33 +114,26 @@ public class CallbackHandlerTest { boolean wide = true; int subId = 5; boolean roaming = true; - mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, typeDescription, - description, wide, subId, roaming); + boolean isEmergency = true; + mHandler.setMobileDataIndicators(status, type, in, out, typeDescription, + subId, roaming, isEmergency); waitForCallbacks(); ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class); - ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<String> typeContentArg = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<Boolean> wideArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class); Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(), - qsArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), inArg.capture(), - outArg.capture(), typeContentArg.capture(), descArg.capture(), wideArg.capture(), - subIdArg.capture(), eq(roaming)); + typeIconArg.capture(), inArg.capture(), + outArg.capture(), typeContentArg.capture(), + subIdArg.capture(), eq(roaming), eq(isEmergency)); assertEquals(status, statusArg.getValue()); - assertEquals(qs, qsArg.getValue()); assertEquals(type, (int) typeIconArg.getValue()); - assertEquals(qsType, (int) qsTypeIconArg.getValue()); assertEquals(in, (boolean) inArg.getValue()); assertEquals(out, (boolean) outArg.getValue()); assertEquals(typeDescription, typeContentArg.getValue()); - assertEquals(description, descArg.getValue()); - assertEquals(wide, (boolean) wideArg.getValue()); assertEquals(subId, (int) subIdArg.getValue()); } 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 505e1d8346fd..b39171e9f720 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 @@ -29,6 +29,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; 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; @@ -45,8 +46,6 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import java.io.PrintWriter; import java.io.StringWriter; @@ -70,7 +69,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { 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_DATA_3G; + protected static final int DEFAULT_QS_ICON = DEFAULT_ICON; protected NetworkControllerImpl mNetworkController; protected MobileSignalController mMobileSignalController; @@ -117,7 +116,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true); when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn( - new NetworkCapabilities[] { mNetCapabilities }); + new NetworkCapabilities[]{mNetCapabilities}); mSignalStrength = mock(SignalStrength.class); mServiceState = mock(ServiceState.class); @@ -175,17 +174,17 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } protected NetworkControllerImpl setUpNoMobileData() { - when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); - NetworkControllerImpl networkControllerNoMobile - = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, mMockTm, - mMockWm, mMockSm, mConfig, mContext.getMainLooper(), mCallbackHandler, - mock(AccessPointControllerImpl.class), - mock(DataUsageController.class), mMockSubDefaults, - mock(DeviceProvisionedController.class)); + when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); + NetworkControllerImpl networkControllerNoMobile + = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, mMockTm, + mMockWm, mMockSm, mConfig, mContext.getMainLooper(), mCallbackHandler, + mock(AccessPointControllerImpl.class), + mock(DataUsageController.class), mMockSubDefaults, + mock(DeviceProvisionedController.class)); - setupNetworkController(); + setupNetworkController(); - return networkControllerNoMobile; + return networkControllerNoMobile; } @@ -308,11 +307,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase { ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class); Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( - any(), - iconArg.capture(), - anyInt(), - typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(), - anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean()); + iconArg.capture(), + typeIconArg.capture(), + dataInArg.capture(), dataOutArg.capture(), + anyString(), anyInt(), anyBoolean(), anyBoolean()); IconState iconState = iconArg.getValue(); int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, false); @@ -335,17 +333,16 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon, - boolean roaming, boolean inet) { + boolean roaming, boolean inet) { ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); // TODO: Verify all fields. Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( iconArg.capture(), - any(), typeIconArg.capture(), - anyInt(), anyBoolean(), anyBoolean(), anyString(), anyString(), anyBoolean(), - anyInt(), eq(roaming)); + anyBoolean(), anyBoolean(), anyString(), + anyInt(), eq(roaming), anyBoolean()); IconState iconState = iconArg.getValue(); int state = icon == -1 ? 0 @@ -356,22 +353,18 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon, - boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut) { + boolean qsVisible, boolean dataIn, boolean dataOut) { ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor<IconState> qsIconArg = ArgumentCaptor.forClass(IconState.class); - ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class); Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( iconArg.capture(), - qsIconArg.capture(), typeIconArg.capture(), - qsTypeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(), - anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean()); + anyString(), anyInt(), anyBoolean(), anyBoolean()); IconState iconState = iconArg.getValue(); @@ -381,17 +374,15 @@ public class NetworkControllerBaseTest extends SysuiTestCase { 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", state, iconState.icon); - assertEquals("Data icon in quick settings", qsTypeIcon, (int) qsTypeIconArg.getValue()); assertEquals("Data direction in in quick settings", dataIn, (boolean) dataInArg.getValue()); assertEquals("Data direction out in quick settings", dataOut, (boolean) dataOutArg.getValue()); } - protected void assertNetworkNameEquals(String expected) { - assertEquals("Network name", expected, mMobileSignalController.getState().networkName); - } + protected void assertNetworkNameEquals(String expected) { + assertEquals("Network name", expected, mMobileSignalController.getState().networkName); + } } 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 dfe00f95fe4d..6470c117f406 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 @@ -1,5 +1,9 @@ package com.android.systemui.statusbar.policy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -11,10 +15,14 @@ import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import com.android.settingslib.net.DataUsageController; +import com.android.systemui.statusbar.phone.SignalDrawable; +import com.android.systemui.statusbar.policy.NetworkController.IconState; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; @SmallTest @RunWith(AndroidJUnit4.class) @@ -116,8 +124,11 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0); setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false); - verifyDataIndicators(TelephonyIcons.ICON_DATA_DISABLED, - TelephonyIcons.QS_ICON_DATA_DISABLED); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( + iconArg.capture(), anyInt(), anyBoolean(), anyBoolean(), any(), anyInt(), + anyBoolean(), anyBoolean()); + assertEquals(SignalDrawable.STATE_CUT, SignalDrawable.getState(iconArg.getValue().icon)); } @Test @@ -129,9 +140,14 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false); when(mMockProvisionController.isUserSetup(anyInt())).thenReturn(false); mUserCallback.onUserSetupChanged(); + waitForIdleSync(); // Don't show the X until the device is setup. - verifyDataIndicators(0, 0); + ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class); + Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( + iconArg.capture(), anyInt(), anyBoolean(), anyBoolean(), any(), anyInt(), + anyBoolean(), anyBoolean()); + assertNotEquals(SignalDrawable.STATE_CUT, SignalDrawable.getState(iconArg.getValue().icon)); } @Test @@ -181,12 +197,12 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataActivity(direction); verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, DEFAULT_ICON, true, - DEFAULT_QS_SIGNAL_STRENGTH, DEFAULT_QS_ICON, in, out); + in, out); } private void verifyDataIndicators(int dataIcon, int qsDataIcon) { verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, dataIcon, - true, DEFAULT_QS_SIGNAL_STRENGTH, qsDataIcon, false, + true, false, false); } 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 1627925ae1bc..e542c371feda 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 @@ -214,7 +214,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { verifyLastQsMobileDataIndicators(true, testStrength, - TelephonyIcons.QS_DATA_1X, false, false); + TelephonyIcons.ICON_1X, false, false); } } @@ -434,7 +434,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { verifyLastQsMobileDataIndicators(true /* visible */, DEFAULT_LEVEL /* icon */, - DEFAULT_QS_ICON /* typeIcon */, + DEFAULT_ICON /* typeIcon */, false /* dataIn */, true /* dataOut */); } 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 73fa5aa180bf..edfa3261a7e8 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 @@ -62,7 +62,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { public void testWifiIcon() { String testSsid = "Test SSID"; setWifiEnabled(true); - verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); + verifyLastWifiIcon(true, WifiIcons.WIFI_DISCONNECTED); setWifiState(true, testSsid); verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); 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..7c3f3245461c 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; @@ -64,6 +68,7 @@ import com.android.server.autofill.ui.AutoFillUI; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.Map; import java.util.Map.Entry; @@ -125,7 +130,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 +161,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. @@ -216,13 +221,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState synchronized (mLock) { mActivityToken = newActivity; mClient = IAutoFillManagerClient.Stub.asInterface(newClient); + + // The tracked id are not persisted in the client, hence update them + updateTrackedIdsLocked(); } } // 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 +251,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 +351,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 +370,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 +402,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 +454,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 +592,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 +714,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 +745,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,20 +753,53 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } - private void processResponseLocked(FillResponse response) { + private void updateTrackedIdsLocked() { + if (mResponses == null || mResponses.size() == 0) { + return; + } + + // Only track the views of the last response as only those are reported back to the + // service, see #showSaveLocked + ArrayList<AutofillId> trackedViews = new ArrayList<>(); + boolean saveOnAllViewsInvisible = false; + SaveInfo saveInfo = mResponses.valueAt(getLastResponseIndex()).getSaveInfo(); + if (saveInfo != null) { + saveOnAllViewsInvisible = saveInfo.saveOnAllViewsInvisible(); + + // We only need to track views if we want to save once they become invisible. + if (saveOnAllViewsInvisible) { + if (saveInfo.getRequiredIds() != null) { + Collections.addAll(trackedViews, saveInfo.getRequiredIds()); + } + + if (saveInfo.getOptionalIds() != null) { + Collections.addAll(trackedViews, saveInfo.getOptionalIds()); + } + } + } + + try { + mClient.setTrackedViews(id, trackedViews, saveOnAllViewsInvisible); + } catch (RemoteException e) { + Slog.w(TAG, "Cannot set tracked ids", e); + } + } + + 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); + updateTrackedIdsLocked(); if (mCurrentViewId == null) { return; @@ -852,7 +914,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 +947,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 +958,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 +1025,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/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index d647c635cbb2..aa5083dfeb15 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -798,6 +798,19 @@ public class BackupManagerService { return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0); } + // We also avoid backups of 'disabled' apps + private static boolean appIsDisabled(ApplicationInfo app, PackageManager pm) { + switch (pm.getApplicationEnabledSetting(app.packageName)) { + case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: + case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: + case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: + return true; + + default: + return false; + } + } + /* does *not* check overall backup eligibility policy! */ private static boolean appGetsFullBackup(PackageInfo pkg) { if (pkg.applicationInfo.backupAgentName != null) { @@ -10774,7 +10787,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); if (!appIsEligibleForBackup(packageInfo.applicationInfo) || - appIsStopped(packageInfo.applicationInfo)) { + appIsStopped(packageInfo.applicationInfo) || + appIsDisabled(packageInfo.applicationInfo, mPackageManager)) { return false; } IBackupTransport transport = mTransportManager.getCurrentTransportBinder(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 50c0a124fb8a..d5adf4856d47 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; @@ -89,7 +90,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; -import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -203,6 +203,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS private final int mReleasePendingIntentDelayMs; + private MockableSystemProperties mSystemProperties; + private Tethering mTethering; private final PermissionMonitor mPermissionMonitor; @@ -675,6 +677,8 @@ public class ConnectivityService extends IConnectivityManager.Stub IpConnectivityLog logger) { if (DBG) log("ConnectivityService starting up"); + mSystemProperties = getSystemProperties(); + mMetricsLog = logger; mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder()); @@ -692,7 +696,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000); - mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS); + mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS); mContext = checkNotNull(context, "missing Context"); mNetd = checkNotNull(netManager, "missing INetworkManagementService"); @@ -722,7 +726,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; // TODO: What is the "correct" way to do determine if this is a wifi only device? - boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false); + boolean wifiOnly = mSystemProperties.getBoolean("ro.radio.noril", false); log("wifiOnly=" + wifiOnly); String[] naStrings = context.getResources().getStringArray( com.android.internal.R.array.networkAttributes); @@ -775,8 +779,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - mTestMode = SystemProperties.get("cm.test.mode").equals("true") - && SystemProperties.get("ro.build.type").equals("eng"); + mTestMode = mSystemProperties.get("cm.test.mode").equals("true") + && mSystemProperties.get("ro.build.type").equals("eng"); mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager, IoThread.get().getLooper(), new MockableSystemProperties()); @@ -1732,8 +1736,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // Overridden for testing purposes to avoid writing to SystemProperties. @VisibleForTesting - protected int getDefaultTcpRwnd() { - return SystemProperties.getInt(DEFAULT_TCP_RWND_KEY, 0); + protected MockableSystemProperties getSystemProperties() { + return new MockableSystemProperties(); } private void updateTcpBufferSizes(NetworkAgentInfo nai) { @@ -1771,10 +1775,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.TCP_DEFAULT_INIT_RWND, getDefaultTcpRwnd()); + Settings.Global.TCP_DEFAULT_INIT_RWND, + mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)); final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd"; if (rwndValue != 0) { - SystemProperties.set(sysctlKey, rwndValue.toString()); + mSystemProperties.set(sysctlKey, rwndValue.toString()); } } @@ -1798,7 +1803,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public int getRestoreDefaultNetworkDelay(int networkType) { - String restoreDefaultNetworkDelayStr = SystemProperties.get( + String restoreDefaultNetworkDelayStr = mSystemProperties.get( NETWORK_RESTORE_DELAY_PROP_NAME); if(restoreDefaultNetworkDelayStr != null && restoreDefaultNetworkDelayStr.length() != 0) { @@ -2965,7 +2970,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public boolean isTetheringSupported() { enforceTetherAccessPermission(); - int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); + int defaultVal = (mSystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.TETHER_SUPPORTED, defaultVal) != 0) && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); @@ -4044,11 +4049,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 +4119,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 +4183,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 +4203,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); @@ -4466,17 +4477,24 @@ public class ConnectivityService extends IConnectivityManager.Stub int last = 0; for (InetAddress dns : dnses) { ++last; - String key = "net.dns" + last; - String value = dns.getHostAddress(); - SystemProperties.set(key, value); + setNetDnsProperty(last, dns.getHostAddress()); } for (int i = last + 1; i <= mNumDnsEntries; ++i) { - String key = "net.dns" + i; - SystemProperties.set(key, ""); + setNetDnsProperty(i, ""); } mNumDnsEntries = last; } + private void setNetDnsProperty(int which, String value) { + final String key = "net.dns" + which; + // Log and forget errors setting unsupported properties. + try { + mSystemProperties.set(key, value); + } catch (Exception e) { + Log.e(TAG, "Error setting unsupported net.dns property: ", e); + } + } + private String getNetworkPermission(NetworkCapabilities nc) { // TODO: make these permission strings AIDL constants instead. if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 2e61550614f2..6502c012ef5b 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -25,7 +25,7 @@ option java_package com.android.server # This is logged when the screen on broadcast has completed 2727 power_screen_broadcast_stop (which|1|5),(wakelockCount|1|1) # This is logged when the screen is turned on or off. -2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1) +2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1),(latency|1|3) # This is logged when the partial wake lock (keeping the device awake # regardless of whether the screen is off) is acquired or released. 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3) diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 39bfedae69d8..8ad3d23648bf 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -49,6 +49,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import android.annotation.BinderThread; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -2146,6 +2147,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); } + @BinderThread @SuppressWarnings("deprecation") @Override public void setImeWindowStatus(IBinder token, IBinder startInputToken, int vis, @@ -2161,9 +2163,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mBackDisposition = backDisposition; updateSystemUiLocked(token, vis, backDisposition); } + + final boolean dismissImeOnBackKeyPressed; + switch (backDisposition) { + case InputMethodService.BACK_DISPOSITION_WILL_DISMISS: + dismissImeOnBackKeyPressed = true; + break; + case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS: + dismissImeOnBackKeyPressed = false; + break; + default: + case InputMethodService.BACK_DISPOSITION_DEFAULT: + dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0); + break; + } mWindowManagerInternal.updateInputMethodWindowStatus(token, (vis & InputMethodService.IME_VISIBLE) != 0, - info != null ? info.mTargetWindow : null); + dismissImeOnBackKeyPressed, info != null ? info.mTargetWindow : null); } private void updateSystemUi(IBinder token, int vis, int backDisposition) { diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d79609856c3f..452fe1d70ddc 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3272,6 +3272,8 @@ class StorageManagerService extends IStorageManager.Stub try { return mContext.getSystemService(StorageStatsManager.class) .queryStatsForUid(volumeUuid, uid).getCacheBytes(); + } catch (IOException e) { + throw new ParcelableException(e); } finally { Binder.restoreCallingIdentity(token); } @@ -3312,6 +3314,8 @@ class StorageManagerService extends IStorageManager.Stub return Math.max(0, path.getUsableSpace() - storage.getStorageLowBytes(path)); } } + } catch (IOException e) { + throw new ParcelableException(e); } finally { Binder.restoreCallingIdentity(token); } @@ -3329,13 +3333,13 @@ class StorageManagerService extends IStorageManager.Stub + " because only " + allocatableBytes + " allocatable")); } - // Free up enough disk space to satisfy both the requested allocation - // and our low disk warning space. - final File path = storage.findPathForUuid(volumeUuid); - bytes += storage.getStorageLowBytes(path); - final long token = Binder.clearCallingIdentity(); try { + // Free up enough disk space to satisfy both the requested allocation + // and our low disk warning space. + final File path = storage.findPathForUuid(volumeUuid); + bytes += storage.getStorageLowBytes(path); + mPms.freeStorage(volumeUuid, bytes, flags); } catch (IOException e) { throw new ParcelableException(e); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c77820b4de3a..2cd14e93791d 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -312,8 +312,7 @@ public final class ActiveServices { } ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, - int id, Notification notification, int callingPid, int callingUid, - boolean fgRequired, String callingPackage, final int userId) + int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId) throws TransactionTooLargeException { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service + " type=" + resolvedType + " args=" + service.getExtras()); @@ -464,10 +463,6 @@ public final class ActiveServices { } ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); - // STOPSHIP deprecated; remove when NotificationManager.startServiceInForeground is retired - if (notification != null) { - setServiceForegroundInnerLocked(r, id, notification, 0); - } return cmp; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2be53136bb74..d43fa0123925 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1230,6 +1230,20 @@ public class ActivityManagerService extends IActivityManager.Stub */ int[] mDeviceIdleTempWhitelist = new int[0]; + static final class PendingTempWhitelist { + final int targetUid; + final long duration; + final String tag; + + PendingTempWhitelist(int _targetUid, long _duration, String _tag) { + targetUid = _targetUid; + duration = _duration; + tag = _tag; + } + } + + final SparseArray<PendingTempWhitelist> mPendingTempWhitelist = new SparseArray<>(); + /** * Information about and control over application operations */ @@ -1688,6 +1702,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int NOTIFY_VR_SLEEPING_MSG = 65; static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66; static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67; + static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int START_USER_SWITCH_FG_MSG = 712; static final int FIRST_ACTIVITY_STACK_MSG = 100; @@ -1921,6 +1936,9 @@ public class ActivityManagerService extends IActivityManager.Stub case DISPATCH_UIDS_CHANGED_UI_MSG: { dispatchUidsChanged(); } break; + case PUSH_TEMP_WHITELIST_UI_MSG: { + pushTempWhitelist(); + } break; } } } @@ -6493,7 +6511,8 @@ public class ActivityManagerService extends IActivityManager.Stub // This is the first appearance of the uid, report it now! if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Creating new process uid: " + uidRec); - if (Arrays.binarySearch(mDeviceIdleTempWhitelist, UserHandle.getAppId(proc.uid)) >= 0) { + if (Arrays.binarySearch(mDeviceIdleTempWhitelist, UserHandle.getAppId(proc.uid)) >= 0 + || mPendingTempWhitelist.indexOfKey(proc.uid) >= 0) { uidRec.setWhitelist = uidRec.curWhitelist = true; } uidRec.updateHasInternetPermission(); @@ -7487,43 +7506,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - /** - * Whitelists {@code targetUid} to temporarily bypass Power Save mode. - */ - void tempWhitelistAppForPowerSave(int callerPid, int callerUid, int targetUid, long duration) { - if (DEBUG_WHITELISTS) { - Slog.d(TAG, "tempWhitelistAppForPowerSave(" + callerPid + ", " + callerUid + ", " - + targetUid + ", " + duration + ")"); - } - - if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid) - != PackageManager.PERMISSION_GRANTED) { - synchronized (mPidsSelfLocked) { - final ProcessRecord pr = mPidsSelfLocked.get(callerPid); - if (pr == null) { - Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid " - + callerPid); - return; - } - if (!pr.whitelistManager) { - if (DEBUG_WHITELISTS) { - Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid - + ": pid " + callerPid + " is not allowed"); - } - return; - } - } - } - - final long token = Binder.clearCallingIdentity(); - try { - mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(targetUid, duration, - true, "pe from uid:" + callerUid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - @Override public void cancelIntentSender(IIntentSender sender) { if (!(sender instanceof PendingIntentRecord)) { @@ -7863,7 +7845,14 @@ public class ActivityManagerService extends IActivityManager.Stub r.pictureInPictureArgs.copyOnlySet(args); final float aspectRatio = r.pictureInPictureArgs.getAspectRatio(); final List<RemoteAction> actions = r.pictureInPictureArgs.getActions(); - final Rect sourceBounds = r.pictureInPictureArgs.getSourceRectHint(); + // Adjust the source bounds by the insets for the transition down + final Rect sourceBounds = new Rect(r.pictureInPictureArgs.getSourceRectHint()); + final Rect insets = r.pictureInPictureArgs.getSourceRectHintInsets(); + if (insets != null) { + sourceBounds.offsetTo(Math.max(0, sourceBounds.left - insets.left), + Math.max(0, sourceBounds.top - insets.top)); + } + mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, aspectRatio, true /* moveHomeStackToFront */, "enterPictureInPictureMode"); final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID); @@ -8412,7 +8401,8 @@ public class ActivityManagerService extends IActivityManager.Stub boolean isOnDeviceIdleWhitelistLocked(int uid) { final int appId = UserHandle.getAppId(uid); return Arrays.binarySearch(mDeviceIdleWhitelist, appId) >= 0 - || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0; + || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0 + || mPendingTempWhitelist.indexOfKey(uid) >= 0; } private ProviderInfo getProviderInfoLocked(String authority, int userHandle, int pmFlags) { @@ -10535,8 +10525,9 @@ public class ActivityManagerService extends IActivityManager.Stub final PinnedActivityStack pinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID); if (pinnedStack != null) { - pinnedStack.animateResizePinnedStack(null /* sourceBounds */, - destBounds, animationDuration); + pinnedStack.animateResizePinnedStack(null /* sourceHintBounds */, + destBounds, animationDuration, + false /* schedulePipModeChangedOnAnimationEnd */); } } else { throw new IllegalArgumentException("Stack: " + stackId @@ -15587,6 +15578,18 @@ public class ActivityManagerService extends IActivityManager.Stub } pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist)); pw.println(" mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist)); + if (mPendingTempWhitelist.size() > 0) { + pw.println(" mPendingTempWhitelist:"); + for (int i = 0; i < mPendingTempWhitelist.size(); i++) { + PendingTempWhitelist ptw = mPendingTempWhitelist.valueAt(i); + pw.print(" "); + UserHandle.formatUid(pw, ptw.targetUid); + pw.print(": "); + TimeUtils.formatDuration(ptw.duration, pw); + pw.print(" "); + pw.println(ptw.tag); + } + } } if (dumpPackage == null) { pw.println(" mWakefulness=" @@ -17928,8 +17931,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType, int id, Notification notification, boolean requireForeground, - String callingPackage, int userId) + String resolvedType, boolean requireForeground, String callingPackage, int userId) throws TransactionTooLargeException { enforceNotIsolatedCaller("startService"); // Refuse possible leaked file descriptors @@ -17950,7 +17952,7 @@ public class ActivityManagerService extends IActivityManager.Stub ComponentName res; try { res = mServices.startServiceLocked(caller, service, - resolvedType, id, notification, callingPid, callingUid, + resolvedType, callingPid, callingUid, requireForeground, callingPackage, userId); } finally { Binder.restoreCallingIdentity(origId); @@ -17969,7 +17971,7 @@ public class ActivityManagerService extends IActivityManager.Stub ComponentName res; try { res = mServices.startServiceLocked(null, service, - resolvedType, 0, null, -1, uid, fgRequired, callingPackage, userId); + resolvedType, -1, uid, fgRequired, callingPackage, userId); } finally { Binder.restoreCallingIdentity(origId); } @@ -22699,6 +22701,80 @@ public class ActivityManagerService extends IActivityManager.Stub enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE); } + /** + * Whitelists {@code targetUid} to temporarily bypass Power Save mode. + */ + void tempWhitelistForPendingIntentLocked(int callerPid, int callerUid, int targetUid, + long duration, String tag) { + if (DEBUG_WHITELISTS) { + Slog.d(TAG, "tempWhitelistForPendingIntentLocked(" + callerPid + ", " + callerUid + ", " + + targetUid + ", " + duration + ")"); + } + + synchronized (mPidsSelfLocked) { + final ProcessRecord pr = mPidsSelfLocked.get(callerPid); + if (pr == null) { + Slog.w(TAG, "tempWhitelistForPendingIntentLocked() no ProcessRecord for pid " + + callerPid); + return; + } + if (!pr.whitelistManager) { + if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid) + != PackageManager.PERMISSION_GRANTED) { + if (DEBUG_WHITELISTS) { + Slog.d(TAG, "tempWhitelistForPendingIntentLocked() for target " + targetUid + + ": pid " + callerPid + " is not allowed"); + } + return; + } + } + } + + tempWhitelistUidLocked(targetUid, duration, tag); + } + + /** + * Whitelists {@code targetUid} to temporarily bypass Power Save mode. + */ + void tempWhitelistUidLocked(int targetUid, long duration, String tag) { + mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag)); + setUidTempWhitelistStateLocked(targetUid, true); + mUiHandler.obtainMessage(PUSH_TEMP_WHITELIST_UI_MSG).sendToTarget(); + } + + void pushTempWhitelist() { + final int N; + final PendingTempWhitelist[] list; + + // First copy out the pending changes... we need to leave them in the map for now, + // in case someone needs to check what is coming up while we don't have the lock held. + synchronized(this) { + N = mPendingTempWhitelist.size(); + list = new PendingTempWhitelist[N]; + for (int i = 0; i < N; i++) { + list[i] = mPendingTempWhitelist.valueAt(i); + } + } + + // Now safely dispatch changes to device idle controller. + for (int i = 0; i < N; i++) { + PendingTempWhitelist ptw = list[i]; + mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid, + ptw.duration, true, ptw.tag); + } + + // And now we can safely remove them from the map. + synchronized(this) { + for (int i = 0; i < N; i++) { + PendingTempWhitelist ptw = list[i]; + int index = mPendingTempWhitelist.indexOfKey(ptw.targetUid); + if (index >= 0 && mPendingTempWhitelist.valueAt(index) == ptw) { + mPendingTempWhitelist.removeAt(index); + } + } + } + } + final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) { boolean changed = false; for (int i=mActiveUids.size()-1; i>=0; i--) { @@ -22713,6 +22789,15 @@ public class ActivityManagerService extends IActivityManager.Stub } } + final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) { + boolean changed = false; + final UidRecord uidRec = mActiveUids.get(uid); + if (uidRec != null && uidRec.curWhitelist != onWhitelist) { + uidRec.curWhitelist = onWhitelist; + updateOomAdjLocked(); + } + } + final void trimApplications() { synchronized (this) { int i; @@ -23885,6 +23970,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/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 0fcf3e66debe..b6bfb00d3815 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -524,7 +524,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println("Starting service: " + intent); pw.flush(); ComponentName cn = mInterface.startService(null, intent, intent.getType(), - -1, null, asForeground, SHELL_PACKAGE_NAME, mUserId); + asForeground, SHELL_PACKAGE_NAME, mUserId); if (cn == null) { err.println("Error: Not found; no service started."); return -1; diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 28817878373b..494aaa766b94 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -314,7 +314,8 @@ class ActivityMetricsLogger { builder.setPackageName(info.launchedActivity.packageName); builder.setType(type); builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name); - if (info.launchedActivity.launchedFromPackage != null) { + final boolean isInstantApp = info.launchedActivity.info.applicationInfo.isInstantApp(); + if (isInstantApp && info.launchedActivity.launchedFromPackage != null) { builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME, info.launchedActivity.launchedFromPackage); } @@ -323,8 +324,7 @@ class ActivityMetricsLogger { info.launchedActivity.info.launchToken); info.launchedActivity.info.launchToken = null; } - builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, - info.launchedActivity.info.applicationInfo.isInstantApp() ? 1 : 0); + builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0); builder.addTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS, mCurrentTransitionDeviceUptime); builder.addTaggedData(APP_TRANSITION_DELAY_MS, mCurrentTransitionDelayMs); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 276b267edb5b..7cdddc0ffeaf 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="); @@ -1170,6 +1178,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo * the activity is not currently visible and {@param noThrow} is not set. */ boolean checkEnterPictureInPictureState(String caller, boolean noThrow, boolean beforeStopping) { + if (!supportsPictureInPicture()) { + return false; + } + // Check app-ops and see if PiP is supported for this package if (!checkEnterPictureInPictureAppOpsState()) { return false; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 4c84d98d468a..85c5c647ceed 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -65,6 +65,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.ASSISTANT_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; +import static com.android.server.am.ActivityStack.ActivityState.STOPPED; +import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; @@ -589,6 +591,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } /** + * Returns whether to defer the scheduling of the multi-window mode. + */ + boolean deferScheduleMultiWindowModeChanged() { + return false; + } + + /** * Defers updating the bounds of the stack. If the stack was resized/repositioned while * deferring, the bounds will update in {@link #continueUpdateBounds()}. */ @@ -1172,7 +1181,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { final ActivityRecord r = activities.get(activityNdx); - if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED + if (r.state == STOPPING || r.state == STOPPED || r.state == ActivityState.PAUSED || r.state == ActivityState.PAUSING) { r.setSleeping(true); } @@ -1355,7 +1364,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev); if (prev != null) { - final boolean wasStopping = prev.state == ActivityState.STOPPING; + final boolean wasStopping = prev.state == STOPPING; prev.state = ActivityState.PAUSED; if (prev.finishing) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev); @@ -1376,7 +1385,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // We are also stopping, the stop request must have gone soon after the pause. // We can't clobber it, because the stop confirmation will not be handled. // We don't need to schedule another stop, we only need to let it happen. - prev.state = ActivityState.STOPPING; + prev.state = STOPPING; } else if ((!prev.visible && !hasVisibleBehindActivity()) || mService.isSleepingOrShuttingDownLocked()) { // If we were visible then resumeTopActivities will release resources before @@ -1995,10 +2004,17 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // keeping the screen frozen. if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state); try { + final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState( + "makeInvisible", true /* noThrow */, true /* beforeStopping */); + // We don't want to call setVisible(false) to avoid notifying the client of this + // intermittent invisible state if it can enter Pip and isn't stopped or stopping. + if (!canEnterPictureInPicture || r.state == STOPPING || r.state == STOPPED) { + r.setVisible(false); + } + switch (r.state) { case STOPPING: case STOPPED: - r.setVisible(false); if (r.app != null && r.app.thread != null) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Scheduling invisibility: " + r); @@ -2017,25 +2033,16 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // This case created for transitioning activities from // translucent to opaque {@link Activity#convertToOpaque}. if (visibleBehind == r) { - r.setVisible(false); releaseBackgroundResources(r); } else { // If this activity is in a state where it can currently enter // picture-in-picture, then don't immediately schedule the idle now in case // the activity tries to enterPictureInPictureMode() later. Otherwise, // we will try and stop the activity next time idle is processed. - final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState( - "makeInvisible", true /* noThrow */, true /* beforeStopping */); if (canEnterPictureInPicture) { - // We set r.visible=false so that Stop will later - // call setVisible for us. In this case - // we don't want to call setVisible(false) to avoid - // notifying the client of this intermittent invisible - // state. + // We set r.visible=false so that Stop will later call setVisible for us r.visible = false; - } else { - r.setVisible(false); } addToStopping(r, true /* scheduleIdle */, canEnterPictureInPicture /* idleDelayed */); @@ -2311,9 +2318,20 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); + final boolean prevCanPip = prev != null && prev.checkEnterPictureInPictureState( + "resumeTopActivity", true /* noThrow */, userLeaving /* beforeStopping */); // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity - // to be paused, while at the same time resuming the new resume activity + // to be paused, while at the same time resuming the new resume activity only if the + // previous activity can't go into Pip since we want to give Pip activities a chance to + // enter Pip before resuming the next activity. final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0; + // TODO: This would be go to have however, the various call points that pass in + // prev need to be corrected first. In some cases the prev is equal to the next e.g. launch + // an app from home. And, is come other cases it is null e.g. press home button after + // launching an app. The doc on the method says prev. is null expect for the case we are + // coming from pause. We need to see if that is a valid thing and also if all the code in + // this method using prev. are setup to function like that. + //&& !prevCanPip; boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false); if (mResumedActivity != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, @@ -3353,11 +3371,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai r.stopped = false; if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPING: " + r + " (stop requested)"); - r.state = ActivityState.STOPPING; + r.state = STOPPING; if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Stopping visible=" + r.visible + " for " + r); if (!r.visible) { - r.setVisibility(false); + r.setVisible(false); } EventLogTags.writeAmStopActivity( r.userId, System.identityHashCode(r), r.shortComponentName); @@ -3375,7 +3393,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Just in case, assume it to be stopped. r.stopped = true; if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r); - r.state = ActivityState.STOPPED; + r.state = STOPPED; if (r.deferRelaunchUntilPaused) { destroyActivityLocked(r, true, "stop-except"); } @@ -3680,7 +3698,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPING: "+ r + " (finish requested)"); - r.state = ActivityState.STOPPING; + r.state = STOPPING; if (oomAdj) { mService.updateOomAdjLocked(); } @@ -3705,8 +3723,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai || (prevState == ActivityState.PAUSED && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID)) || finishingActivityInNonFocusedStack - || prevState == ActivityState.STOPPING - || prevState == ActivityState.STOPPED + || prevState == STOPPING + || prevState == STOPPED || prevState == ActivityState.INITIALIZING) { r.makeFinishingLocked(); boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm"); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 4d16e33ad81c..43ae4b22ba63 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2504,7 +2504,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // incorrect if AMS.resizeStackWithBoundsFromWindowManager() is already called while waiting // for the AMS lock to be freed. So check and make sure these bounds are still good. final PinnedStackWindowController stackController = stack.getWindowContainerController(); - if (stackController.pinnedStackResizeAllowed()) { + if (stackController.pinnedStackResizeDisallowed()) { return; } @@ -2873,7 +2873,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - void moveActivityToPinnedStackLocked(ActivityRecord r, Rect sourceBounds, float aspectRatio, + void moveActivityToPinnedStackLocked(ActivityRecord r, Rect sourceHintBounds, float aspectRatio, boolean moveHomeStackToFront, String reason) { mWindowManager.deferSurfaceLayout(); @@ -2948,11 +2948,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final Rect destBounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY, aspectRatio, false /* useExistingStackBounds */); - // TODO(b/36099777): Schedule the PiP mode change here immediately until we can defer all - // callbacks until after the bounds animation - scheduleUpdatePictureInPictureModeIfNeeded(r.getTask(), destBounds, true /* immediate */); - - stack.animateResizePinnedStack(sourceBounds, destBounds, -1 /* animationDuration */); + stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */, + true /* schedulePipModeChangedOnAnimationEnd */); mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName); } @@ -4179,6 +4176,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } void scheduleUpdateMultiWindowMode(TaskRecord task) { + // If the stack is animating in a way where we will be forcing a multi-mode change at the + // end, then ensure that we defer all in between multi-window mode changes + if (task.getStack().deferScheduleMultiWindowModeChanged()) { + return; + } + for (int i = task.mActivities.size() - 1; i >= 0; i--) { final ActivityRecord r = task.mActivities.get(i); if (r.app != null && r.app.thread != null) { 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/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java index 02ec07561f4f..c9c1d005a85a 100644 --- a/services/core/java/com/android/server/am/AppErrorDialog.java +++ b/services/core/java/com/android/server/am/AppErrorDialog.java @@ -148,18 +148,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { - final int result = msg.what; - - synchronized (mService) { - if (mProc != null && mProc.crashDialog == AppErrorDialog.this) { - mProc.crashDialog = null; - } - } - mResult.set(result); - - // Make sure we don't have time timeout still hanging around. - removeMessages(TIMEOUT); - + setResult(msg.what); dismiss(); } }; @@ -168,11 +157,23 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen public void dismiss() { if (!mResult.mHasResult) { // We are dismissing and the result has not been set...go ahead and set. - mResult.set(FORCE_QUIT); + setResult(FORCE_QUIT); } super.dismiss(); } + private void setResult(int result) { + synchronized (mService) { + if (mProc != null && mProc.crashDialog == AppErrorDialog.this) { + mProc.crashDialog = null; + } + } + mResult.set(result); + + // Make sure we don't have time timeout still hanging around. + mHandler.removeMessages(TIMEOUT); + } + @Override public void onClick(View v) { switch (v.getId()) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index baa71d708caa..349180fd28a9 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -155,8 +155,6 @@ public final class BroadcastQueue { static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG; static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1; - static final int SCHEDULE_TEMP_WHITELIST_MSG - = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 2; final BroadcastHandler mHandler; @@ -178,13 +176,6 @@ public final class BroadcastQueue { broadcastTimeoutLocked(true); } } break; - case SCHEDULE_TEMP_WHITELIST_MSG: { - DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController; - if (dic != null) { - dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1), - msg.arg2, true, (String)msg.obj); - } - } break; } } } @@ -789,12 +780,11 @@ public final class BroadcastQueue { if (r.intent.getAction() != null) { b.append(r.intent.getAction()); } else if (r.intent.getComponent() != null) { - b.append(r.intent.getComponent().flattenToShortString()); + r.intent.getComponent().appendShortString(b); } else if (r.intent.getData() != null) { b.append(r.intent.getData()); } - mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration, b.toString()) - .sendToTarget(); + mService.tempWhitelistUidLocked(uid, duration, b.toString()); } /** diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index c697f2876c65..a580d4bdde5e 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -237,14 +237,6 @@ final class PendingIntentRecord extends IIntentSender.Stub { if (intent != null) intent.setDefusable(true); if (options != null) options.setDefusable(true); - if (whitelistDuration > 0 && !canceled) { - // Must call before acquiring the lock. It's possible the method return before sending - // the intent due to some validations inside the lock, in which case the UID shouldn't - // be whitelisted, but since the whitelist is temporary, that would be ok. - owner.tempWhitelistAppForPowerSave(Binder.getCallingPid(), Binder.getCallingUid(), uid, - whitelistDuration); - } - synchronized (owner) { final ActivityContainer activityContainer = (ActivityContainer)container; if (activityContainer != null && activityContainer.mParentActivity != null && @@ -279,6 +271,22 @@ final class PendingIntentRecord extends IIntentSender.Stub { resolvedType = key.requestResolvedType; } + if (whitelistDuration > 0) { + StringBuilder tag = new StringBuilder(64); + tag.append("pendingintent:"); + UserHandle.formatUid(tag, Binder.getCallingUid()); + tag.append(":"); + if (finalIntent.getAction() != null) { + tag.append(finalIntent.getAction()); + } else if (finalIntent.getComponent() != null) { + finalIntent.getComponent().appendShortString(tag); + } else if (finalIntent.getData() != null) { + tag.append(finalIntent.getData()); + } + owner.tempWhitelistForPendingIntentLocked(Binder.getCallingPid(), + Binder.getCallingUid(), uid, whitelistDuration, tag.toString()); + } + final long origId = Binder.clearCallingIdentity(); boolean sendFinish = finishedReceiver != null; diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java index cd9c42c7c643..a4932bbdd732 100644 --- a/services/core/java/com/android/server/am/PinnedActivityStack.java +++ b/services/core/java/com/android/server/am/PinnedActivityStack.java @@ -43,9 +43,10 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController> return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds); } - void animateResizePinnedStack(Rect sourceBounds, Rect destBounds, int animationDuration) { - getWindowContainerController().animateResizePinnedStack(sourceBounds, destBounds, - animationDuration); + void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration, + boolean schedulePipModeChangedOnAnimationEnd) { + getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds, + animationDuration, schedulePipModeChangedOnAnimationEnd); } void setPictureInPictureAspectRatio(float aspectRatio) { @@ -60,7 +61,18 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController> return getWindowContainerController().isAnimatingBoundsToFullscreen(); } - @Override + /** + * Returns whether to defer the scheduling of the multi-window mode. + */ + boolean deferScheduleMultiWindowModeChanged() { + // For the pinned stack, the deferring of the multi-window mode changed is tied to the + // transition animation into picture-in-picture, and is called once the animation completes, + // or is interrupted in a way that would leave the stack in a non-fullscreen state. + // @see BoundsAnimationController + // @see BoundsAnimationControllerTests + return mWindowContainerController.deferScheduleMultiWindowModeChanged(); + } + public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) { // It is guaranteed that the activities requiring the update will be in the pinned stack at // this point (either reparented before the animation into PiP, or before reparenting after diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 268724283351..aa1b74ce4577 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -520,7 +520,11 @@ public class AudioService extends IAudioService.Stub private int mPrevVolDirection = AudioManager.ADJUST_SAME; // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume // is controlled by Vol keys. - private int mVolumeControlStream = -1; + private int mVolumeControlStream = -1; + // interpretation of whether the volume stream has been selected by the user by clicking on a + // volume slider to change which volume is controlled by the volume keys. Is false + // when mVolumeControlStream is -1. + private boolean mUserSelectedVolumeControlStream = false; private final Object mForceControlStreamLock = new Object(); // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system // server process so in theory it is not necessary to monitor the client death. @@ -929,11 +933,8 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { - if (streamType != mStreamVolumeAlias[streamType]) { - mStreamStates[streamType]. - setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], - TAG); - } + mStreamStates[streamType] + .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG); // apply stream volume if (!mStreamStates[streamType].mIsMuted) { mStreamStates[streamType].applyAllVolumes(); @@ -1022,20 +1023,21 @@ public class AudioService extends IAudioService.Stub } mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; - final int oldStreamA11yAlias = mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY]; - if (oldStreamA11yAlias != a11yStreamAlias) { - mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias; - mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName = - System.VOLUME_SETTINGS_INT[a11yStreamAlias]; - // restore the value from the settings when the alias changes - mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings(); - } + mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias; if (updateVolumes) { mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], caller); + + mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName = + System.VOLUME_SETTINGS_INT[a11yStreamAlias]; mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes( mStreamStates[a11yStreamAlias], caller); + if (sIndependentA11yVolume) { + // restore the a11y values from the settings + mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings(); + } + // apply stream mute states according to new value of mRingerModeAffectedStreams setRingerModeInt(getRingerModeInternal(), false); sendMsg(mAudioHandler, @@ -1226,14 +1228,29 @@ public class AudioService extends IAudioService.Stub private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller, int uid) { if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType - + ", flags=" + flags + ", caller=" + caller); - int streamType; - boolean isMute = isMuteAdjust(direction); - if (mVolumeControlStream != -1) { + + ", flags=" + flags + ", caller=" + caller + + ", volControlStream=" + mVolumeControlStream + + ", userSelect=" + mUserSelectedVolumeControlStream); + final int streamType; + if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1 streamType = mVolumeControlStream; } else { - streamType = getActiveStreamType(suggestedStreamType); + final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType); + final boolean activeForReal; + if (maybeActiveStreamType == AudioSystem.STREAM_MUSIC) { + activeForReal = isAfMusicActiveRecently(0); + } else { + activeForReal = AudioSystem.isStreamActive(maybeActiveStreamType, 0); + } + if (activeForReal || mVolumeControlStream == -1) { + streamType = maybeActiveStreamType; + } else { + streamType = mVolumeControlStream; + } } + + final boolean isMute = isMuteAdjust(direction); + ensureValidStreamType(streamType); final int resolvedStream = mStreamVolumeAlias[streamType]; @@ -1709,13 +1726,18 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#forceVolumeControlStream(int) */ public void forceVolumeControlStream(int streamType, IBinder cb) { + if (DEBUG_VOL) { Log.d(TAG, String.format("forceVolumeControlStream(%d)", streamType)); } synchronized(mForceControlStreamLock) { + if (mVolumeControlStream != -1 && streamType != -1) { + mUserSelectedVolumeControlStream = true; + } mVolumeControlStream = streamType; if (mVolumeControlStream == -1) { if (mForceControlStreamClient != null) { mForceControlStreamClient.release(); mForceControlStreamClient = null; } + mUserSelectedVolumeControlStream = false; } else { mForceControlStreamClient = new ForceControlStreamClient(cb); } @@ -1746,6 +1768,7 @@ public class AudioService extends IAudioService.Stub } else { mForceControlStreamClient = null; mVolumeControlStream = -1; + mUserSelectedVolumeControlStream = false; } } } @@ -4228,7 +4251,17 @@ public class AudioService extends IAudioService.Stub return mIndexMin; } + /** + * Copies all device/index pairs from the given VolumeStreamState after initializing + * them with the volume for DEVICE_OUT_DEFAULT. No-op if the source VolumeStreamState + * has the same stream type as this instance. + * @param srcStream + * @param caller + */ public void setAllIndexes(VolumeStreamState srcStream, String caller) { + if (mStreamType == srcStream.mStreamType) { + return; + } synchronized (VolumeStreamState.class) { int srcStreamType = srcStream.getStreamType(); // apply default device volume from source stream to all devices first in case diff --git a/services/core/java/com/android/server/connectivity/MockableSystemProperties.java b/services/core/java/com/android/server/connectivity/MockableSystemProperties.java index 4f68652d412c..77b86d8e4355 100644 --- a/services/core/java/com/android/server/connectivity/MockableSystemProperties.java +++ b/services/core/java/com/android/server/connectivity/MockableSystemProperties.java @@ -19,7 +19,20 @@ package com.android.server.connectivity; import android.os.SystemProperties; public class MockableSystemProperties { + + public String get(String key) { + return SystemProperties.get(key); + } + + public int getInt(String key, int def) { + return SystemProperties.getInt(key, def); + } + public boolean getBoolean(String key, boolean def) { return SystemProperties.getBoolean(key, def); } + + public void set(String key, String value) { + SystemProperties.set(key, value); + } } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 1ffa86440ae2..601ed010a696 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -78,7 +78,6 @@ public class TetherInterfaceStateMachine extends StateMachine { public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13; private final State mInitialState; - private final State mServingState; private final State mLocalHotspotState; private final State mTetheredState; private final State mUnavailableState; @@ -107,14 +106,12 @@ public class TetherInterfaceStateMachine extends StateMachine { mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; mInitialState = new InitialState(); - mServingState = new ServingState(); mLocalHotspotState = new LocalHotspotState(); mTetheredState = new TetheredState(); mUnavailableState = new UnavailableState(); addState(mInitialState); - addState(mServingState); - addState(mLocalHotspotState, mServingState); - addState(mTetheredState, mServingState); + addState(mLocalHotspotState); + addState(mTetheredState); addState(mUnavailableState); setInitialState(mInitialState); @@ -222,12 +219,11 @@ public class TetherInterfaceStateMachine extends StateMachine { } } - class ServingState extends State { + class BaseServingState extends State { @Override public void enter() { if (!configureIfaceIp(true)) { mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR; - transitionTo(mInitialState); return; } @@ -236,12 +232,13 @@ public class TetherInterfaceStateMachine extends StateMachine { } catch (Exception e) { Log.e(TAG, "Error Tethering: " + e.toString()); mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; - transitionTo(mInitialState); return; } if (!mIPv6TetherSvc.start()) { Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices"); + // TODO: Make this a fatal error once Bluetooth IPv6 is sorted. + return; } } @@ -254,9 +251,9 @@ public class TetherInterfaceStateMachine extends StateMachine { try { mNMService.untetherInterface(mIfaceName); - } catch (Exception ee) { + } catch (Exception e) { mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; - Log.e(TAG, "Failed to untether interface: " + ee.toString()); + Log.e(TAG, "Failed to untether interface: " + e.toString()); } configureIfaceIp(false); @@ -293,15 +290,27 @@ public class TetherInterfaceStateMachine extends StateMachine { } } - class LocalHotspotState extends State { + // Handling errors in BaseServingState.enter() by transitioning is + // problematic because transitioning during a multi-state jump yields + // a Log.wtf(). Ultimately, there should be only one ServingState, + // and forwarding and NAT rules should be handled by a coordinating + // functional element outside of TetherInterfaceStateMachine. + class LocalHotspotState extends BaseServingState { @Override public void enter() { + super.enter(); + if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + transitionTo(mInitialState); + } + if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName); sendInterfaceState(IControlsTethering.STATE_LOCAL_HOTSPOT); } @Override public boolean processMessage(Message message) { + if (super.processMessage(message)) return true; + maybeLogMessage(this, message.what); switch (message.what) { case CMD_TETHER_REQUESTED: @@ -317,9 +326,19 @@ public class TetherInterfaceStateMachine extends StateMachine { } } - class TetheredState extends State { + // Handling errors in BaseServingState.enter() by transitioning is + // problematic because transitioning during a multi-state jump yields + // a Log.wtf(). Ultimately, there should be only one ServingState, + // and forwarding and NAT rules should be handled by a coordinating + // functional element outside of TetherInterfaceStateMachine. + class TetheredState extends BaseServingState { @Override public void enter() { + super.enter(); + if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + transitionTo(mInitialState); + } + if (DBG) Log.d(TAG, "Tethered " + mIfaceName); sendInterfaceState(IControlsTethering.STATE_TETHERED); } @@ -327,6 +346,7 @@ public class TetherInterfaceStateMachine extends StateMachine { @Override public void exit() { cleanupUpstream(); + super.exit(); } private void cleanupUpstream() { @@ -361,6 +381,8 @@ public class TetherInterfaceStateMachine extends StateMachine { @Override public boolean processMessage(Message message) { + if (super.processMessage(message)) return true; + maybeLogMessage(this, message.what); boolean retValue = true; switch (message.what) { 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/GrantedUriPermissions.java b/services/core/java/com/android/server/job/GrantedUriPermissions.java new file mode 100644 index 000000000000..e413d8d1d8c0 --- /dev/null +++ b/services/core/java/com/android/server/job/GrantedUriPermissions.java @@ -0,0 +1,156 @@ +/* + * 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.server.job; + +import android.app.IActivityManager; +import android.content.ClipData; +import android.content.ContentProvider; +import android.content.Intent; +import android.net.Uri; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; + +import java.io.PrintWriter; +import java.util.ArrayList; + +public class GrantedUriPermissions { + private final int mGrantFlags; + private final int mSourceUserId; + private final String mTag; + private final IBinder mPermissionOwner; + private final ArrayList<Uri> mUris = new ArrayList<>(); + + private GrantedUriPermissions(IActivityManager am, int grantFlags, int uid, String tag) + throws RemoteException { + mGrantFlags = grantFlags; + mSourceUserId = UserHandle.getUserId(uid); + mTag = tag; + mPermissionOwner = am.newUriPermissionOwner("job: " + tag); + } + + public void revoke(IActivityManager am) { + for (int i = mUris.size()-1; i >= 0; i--) { + try { + am.revokeUriPermissionFromOwner(mPermissionOwner, mUris.get(i), + mGrantFlags, mSourceUserId); + } catch (RemoteException e) { + } + } + mUris.clear(); + } + + public static boolean checkGrantFlags(int grantFlags) { + return (grantFlags & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION + |Intent.FLAG_GRANT_READ_URI_PERMISSION)) != 0; + } + + public static GrantedUriPermissions createFromIntent(IActivityManager am, Intent intent, + int sourceUid, String targetPackage, int targetUserId, String tag) { + int grantFlags = intent.getFlags(); + if (!checkGrantFlags(grantFlags)) { + return null; + } + + GrantedUriPermissions perms = null; + + Uri data = intent.getData(); + if (data != null) { + perms = grantUri(am, data, sourceUid, targetPackage, targetUserId, grantFlags, tag, + perms); + } + + ClipData clip = intent.getClipData(); + if (clip != null) { + perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, tag, + perms); + } + + return perms; + } + + public static GrantedUriPermissions createFromClip(IActivityManager am, ClipData clip, + int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag) { + if (!checkGrantFlags(grantFlags)) { + return null; + } + GrantedUriPermissions perms = null; + if (clip != null) { + perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, + tag, perms); + } + return perms; + } + + private static GrantedUriPermissions grantClip(IActivityManager am, ClipData clip, + int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, + GrantedUriPermissions curPerms) { + final int N = clip.getItemCount(); + for (int i = 0; i < N; i++) { + curPerms = grantItem(am, clip.getItemAt(i), sourceUid, targetPackage, targetUserId, + grantFlags, tag, curPerms); + } + return curPerms; + } + + private static GrantedUriPermissions grantUri(IActivityManager am, Uri uri, + int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, + GrantedUriPermissions curPerms) { + try { + int sourceUserId = ContentProvider.getUserIdFromUri(uri, + UserHandle.getUserId(sourceUid)); + uri = ContentProvider.getUriWithoutUserId(uri); + if (curPerms == null) { + curPerms = new GrantedUriPermissions(am, grantFlags, sourceUid, tag); + } + am.grantUriPermissionFromOwner(curPerms.mPermissionOwner, sourceUid, targetPackage, + uri, grantFlags, sourceUserId, targetUserId); + curPerms.mUris.add(uri); + } catch (RemoteException e) { + Slog.e("JobScheduler", "AM dead"); + } + return curPerms; + } + + private static GrantedUriPermissions grantItem(IActivityManager am, ClipData.Item item, + int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, + GrantedUriPermissions curPerms) { + if (item.getUri() != null) { + curPerms = grantUri(am, item.getUri(), sourceUid, targetPackage, targetUserId, + grantFlags, tag, curPerms); + } + Intent intent = item.getIntent(); + if (intent != null && intent.getData() != null) { + curPerms = grantUri(am, intent.getData(), sourceUid, targetPackage, targetUserId, + grantFlags, tag, curPerms); + } + return curPerms; + } + + // Dumpsys infrastructure + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("mGrantFlags=0x"); pw.print(Integer.toHexString(mGrantFlags)); + pw.print(" mSourceUserId="); pw.println(mSourceUserId); + pw.print(prefix); pw.print("mTag="); pw.println(mTag); + pw.print(prefix); pw.print("mPermissionOwner="); pw.println(mPermissionOwner); + for (int i = 0; i < mUris.size(); i++) { + pw.print(prefix); pw.print("#"); pw.print(i); pw.print(": "); + pw.println(mUris.get(i)); + } + } +} diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index d01de3c9157d..c8bfa345af10 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -601,7 +601,7 @@ public final class JobSchedulerService extends com.android.server.SystemService // Fast path: we are adding work to an existing job, and the JobInfo is not // changing. We can just directly enqueue this work in to the job. if (toCancel.getJob().equals(job)) { - toCancel.enqueueWorkLocked(work); + toCancel.enqueueWorkLocked(ActivityManager.getService(), work); return JobScheduler.RESULT_SUCCESS; } } @@ -625,7 +625,7 @@ public final class JobSchedulerService extends com.android.server.SystemService } if (work != null) { // If work has been supplied, enqueue it into the new job. - jobStatus.enqueueWorkLocked(work); + jobStatus.enqueueWorkLocked(ActivityManager.getService(), work); } startTrackingJobLocked(jobStatus, toCancel); mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); @@ -758,7 +758,7 @@ public final class JobSchedulerService extends com.android.server.SystemService final JobStatus executing = jsc.getRunningJob(); if (executing != null && (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) { - jsc.cancelExecutingJob(JobParameters.REASON_DEVICE_IDLE); + jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE); } } } else { @@ -921,7 +921,7 @@ public final class JobSchedulerService extends com.android.server.SystemService private boolean stopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean writeBack) { // Deal with any remaining work items in the old job. - jobStatus.stopTrackingJobLocked(incomingJob); + jobStatus.stopTrackingJobLocked(ActivityManager.getService(), incomingJob); // Remove from store as well as controllers. final boolean removed = mJobs.remove(jobStatus, writeBack); @@ -939,7 +939,7 @@ public final class JobSchedulerService extends com.android.server.SystemService JobServiceContext jsc = mActiveServices.get(i); final JobStatus executing = jsc.getRunningJob(); if (executing != null && executing.matches(job.getUid(), job.getJobId())) { - jsc.cancelExecutingJob(reason); + jsc.cancelExecutingJobLocked(reason); return true; } } @@ -1071,9 +1071,16 @@ public final class JobSchedulerService extends com.android.server.SystemService if (DEBUG) { Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule); } + + // If the job wants to be rescheduled, we first need to make the next upcoming + // job so we can transfer any appropriate state over from the previous job when + // we stop it. + final JobStatus rescheduledJob = needsReschedule + ? getRescheduleJobForFailureLocked(jobStatus) : null; + // Do not write back immediately if this is a periodic job. The job may get lost if system // shuts down before it is added back. - if (!stopTrackingJobLocked(jobStatus, null, !jobStatus.getJob().isPeriodic())) { + if (!stopTrackingJobLocked(jobStatus, rescheduledJob, !jobStatus.getJob().isPeriodic())) { if (DEBUG) { Slog.d(TAG, "Could not find job to remove. Was job removed while executing?"); } @@ -1082,18 +1089,14 @@ public final class JobSchedulerService extends com.android.server.SystemService mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget(); return; } - // Note: there is a small window of time in here where, when rescheduling a job, - // we will stop monitoring its content providers. This should be fixed by stopping - // the old job after scheduling the new one, but since we have no lock held here - // that may cause ordering problems if the app removes jobStatus while in here. - if (needsReschedule) { - JobStatus rescheduled = getRescheduleJobForFailureLocked(jobStatus); + + if (rescheduledJob != null) { try { - rescheduled.prepareLocked(ActivityManager.getService()); + rescheduledJob.prepareLocked(ActivityManager.getService()); } catch (SecurityException e) { - Slog.w(TAG, "Unable to regrant job permissions for " + rescheduled); + Slog.w(TAG, "Unable to regrant job permissions for " + rescheduledJob); } - startTrackingJobLocked(rescheduled, jobStatus); + startTrackingJobLocked(rescheduledJob, jobStatus); } else if (jobStatus.getJob().isPeriodic()) { JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus); try { @@ -1561,7 +1564,7 @@ public final class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJob()); } // preferredUid will be set to uid of currently running job. - mActiveServices.get(i).preemptExecutingJob(); + mActiveServices.get(i).preemptExecutingJobLocked(); preservePreferredUid = true; } else { final JobStatus pendingJob = contextIdToJobMap[i]; diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java index c7ef0e26971f..9144966da409 100644 --- a/services/core/java/com/android/server/job/JobServiceContext.java +++ b/services/core/java/com/android/server/job/JobServiceContext.java @@ -44,8 +44,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.server.job.controllers.JobStatus; -import java.util.concurrent.atomic.AtomicBoolean; - /** * Handles client binding and lifecycle of a job. Jobs execute one at a time on an instance of this * class. @@ -56,19 +54,15 @@ import java.util.concurrent.atomic.AtomicBoolean; * job lands, and again when it is complete. * - Cancelling is trickier, because there are also interactions from the client. It's possible * the {@link com.android.server.job.JobServiceContext.JobServiceHandler} tries to process a - * {@link #MSG_CANCEL} after the client has already finished. This is handled by having - * {@link com.android.server.job.JobServiceContext.JobServiceHandler#handleCancelH} check whether + * {@link #doCancelLocked(int)} after the client has already finished. This is handled by having + * {@link com.android.server.job.JobServiceContext.JobServiceHandler#handleCancelLocked} check whether * the context is still valid. - * To mitigate this, tearing down the context removes all messages from the handler, including any - * tardy {@link #MSG_CANCEL}s. Additionally, we avoid sending duplicate onStopJob() + * To mitigate this, we avoid sending duplicate onStopJob() * calls to the client after they've specified jobFinished(). */ public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection { private static final boolean DEBUG = JobSchedulerService.DEBUG; private static final String TAG = "JobServiceContext"; - /** Define the maximum # of jobs allowed to run on a service at once. */ - private static final int defaultMaxActiveJobsPerService = - ActivityManager.isLowRamDeviceStatic() ? 1 : 3; /** Amount of time a job is allowed to execute for before being considered timed-out. */ private static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000; // 10mins. /** Amount of time the JobScheduler waits for the initial service launch+bind. */ @@ -90,14 +84,6 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne // Messages that result from interactions with the client service. /** System timed out waiting for a response. */ private static final int MSG_TIMEOUT = 0; - /** Received a callback from client. */ - private static final int MSG_CALLBACK = 1; - /** Run through list and start any ready jobs.*/ - private static final int MSG_SERVICE_BOUND = 2; - /** Cancel a job. */ - private static final int MSG_CANCEL = 3; - /** Shutdown the job. Used when the client crashes and we can't die gracefully.*/ - private static final int MSG_SHUTDOWN_EXECUTION = 4; public static final int NO_PREFERRED_UID = -1; @@ -115,7 +101,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne private JobParameters mParams; @VisibleForTesting int mVerb; - private AtomicBoolean mCancelled = new AtomicBoolean(); + private boolean mCancelled; /** * All the information maintained about the job currently being executed. @@ -245,14 +231,12 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne } /** Called externally when a job that was scheduled for execution should be cancelled. */ - void cancelExecutingJob(int reason) { - mCallbackHandler.obtainMessage(MSG_CANCEL, reason, 0 /* unused */).sendToTarget(); + void cancelExecutingJobLocked(int reason) { + doCancelLocked(reason); } - void preemptExecutingJob() { - Message m = mCallbackHandler.obtainMessage(MSG_CANCEL); - m.arg1 = JobParameters.REASON_PREEMPT; - m.sendToTarget(); + void preemptExecutingJobLocked() { + doCancelLocked(JobParameters.REASON_PREEMPT); } int getPreferredUid() { @@ -273,59 +257,54 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne @Override public void jobFinished(int jobId, boolean reschedule) { - if (!verifyCallingUid()) { - return; - } - mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0) - .sendToTarget(); + doCallback(reschedule); } @Override public void acknowledgeStopMessage(int jobId, boolean reschedule) { - if (!verifyCallingUid()) { - return; - } - mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0) - .sendToTarget(); + doCallback(reschedule); } @Override public void acknowledgeStartMessage(int jobId, boolean ongoing) { - if (!verifyCallingUid()) { - return; - } - mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, ongoing ? 1 : 0).sendToTarget(); + doCallback(ongoing); } @Override public JobWorkItem dequeueWork(int jobId) { - if (!verifyCallingUid()) { - throw new SecurityException("Bad calling uid: " + Binder.getCallingUid()); - } - JobWorkItem work = null; - boolean stillWorking = false; - synchronized (mLock) { - if (mRunningJob != null) { - work = mRunningJob.dequeueWorkLocked(); - stillWorking = mRunningJob.hasExecutingWorkLocked(); + final int callingUid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + if (!verifyCallingUidLocked(callingUid)) { + throw new SecurityException("Bad calling uid: " + callingUid); + } + + final JobWorkItem work = mRunningJob.dequeueWorkLocked(); + if (work == null && !mRunningJob.hasExecutingWorkLocked()) { + // This will finish the job. + doCallbackLocked(false); + } + return work; } + } finally { + Binder.restoreCallingIdentity(ident); } - if (work == null && !stillWorking) { - jobFinished(jobId, false); - } - return work; } @Override public boolean completeWork(int jobId, int workId) { - if (!verifyCallingUid()) { - throw new SecurityException("Bad calling uid: " + Binder.getCallingUid()); - } - synchronized (mLock) { - if (mRunningJob != null) { - return mRunningJob.completeWorkLocked(workId); + final int callingUid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + if (!verifyCallingUidLocked(callingUid)) { + throw new SecurityException("Bad calling uid: " + callingUid); + } + return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId); } - return false; + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -344,20 +323,20 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne // looper and at this point we can't get any binder callbacks from the client. Better // safe than sorry. runningJob = mRunningJob; - } - if (runningJob == null || !name.equals(runningJob.getServiceComponent())) { - mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget(); - return; - } - this.service = IJobService.Stub.asInterface(service); - final PowerManager pm = - (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, - runningJob.getTag()); - wl.setWorkSource(new WorkSource(runningJob.getSourceUid())); - wl.setReferenceCounted(false); - wl.acquire(); - synchronized (mLock) { + + if (runningJob == null || !name.equals(runningJob.getServiceComponent())) { + closeAndCleanupJobLocked(true /* needsReschedule */); + return; + } + this.service = IJobService.Stub.asInterface(service); + final PowerManager pm = + (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + runningJob.getTag()); + wl.setWorkSource(new WorkSource(runningJob.getSourceUid())); + wl.setReferenceCounted(false); + wl.acquire(); + // We use a new wakelock instance per job. In rare cases there is a race between // teardown following job completion/cancellation and new job service spin-up // such that if we simply assign mWakeLock to be the new instance, we orphan @@ -369,14 +348,16 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mWakeLock.release(); } mWakeLock = wl; + doServiceBoundLocked(); } - mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget(); } /** If the client service crashes we reschedule this job and clean up. */ @Override public void onServiceDisconnected(ComponentName name) { - mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget(); + synchronized (mLock) { + closeAndCleanupJobLocked(true /* needsReschedule */); + } } /** @@ -384,22 +365,18 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne * whether the client exercising the callback is the client we expect. * @return True if the binder calling is coming from the client we expect. */ - private boolean verifyCallingUid() { - synchronized (mLock) { - if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) { - if (DEBUG) { - Slog.d(TAG, "Stale callback received, ignoring."); - } - return false; + private boolean verifyCallingUidLocked(final int callingUid) { + if (mRunningJob == null || callingUid != mRunningJob.getUid()) { + if (DEBUG) { + Slog.d(TAG, "Stale callback received, ignoring."); } - return true; + return false; } + return true; } /** - * Handles the lifecycle of the JobService binding/callbacks, etc. The convention within this - * class is to append 'H' to each function name that can only be called on this handler. This - * isn't strictly necessary because all of these functions are private, but helps clarity. + * Scheduling of async messages (basically timeouts at this point). */ private class JobServiceHandler extends Handler { JobServiceHandler(Looper looper) { @@ -409,293 +386,277 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne @Override public void handleMessage(Message message) { switch (message.what) { - case MSG_SERVICE_BOUND: - doServiceBound(); - break; - case MSG_CALLBACK: - doCallback(message.arg2); - break; - case MSG_CANCEL: - doCancel(message.arg1); - break; case MSG_TIMEOUT: synchronized (mLock) { - handleOpTimeoutH(); + handleOpTimeoutLocked(); } break; - case MSG_SHUTDOWN_EXECUTION: - closeAndCleanupJobH(true /* needsReschedule */); - break; default: Slog.e(TAG, "Unrecognised message: " + message); } } + } - void doServiceBound() { + void doServiceBoundLocked() { + removeOpTimeOutLocked(); + handleServiceBoundLocked(); + } + + void doCallback(boolean reschedule) { + final int callingUid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { synchronized (mLock) { - removeOpTimeOutLocked(); - handleServiceBoundH(); + if (!verifyCallingUidLocked(callingUid)) { + return; + } + doCallbackLocked(reschedule); } + } finally { + Binder.restoreCallingIdentity(ident); } + } - void doCallback(int arg2) { - synchronized (mLock) { - if (DEBUG) { - Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob - + " v:" + VERB_STRINGS[mVerb]); - } - removeOpTimeOutLocked(); + void doCallbackLocked(boolean reschedule) { + if (DEBUG) { + Slog.d(TAG, "doCallback of : " + mRunningJob + + " v:" + VERB_STRINGS[mVerb]); + } + removeOpTimeOutLocked(); - if (mVerb == VERB_STARTING) { - final boolean workOngoing = arg2 == 1; - handleStartedH(workOngoing); - } else if (mVerb == VERB_EXECUTING || - mVerb == VERB_STOPPING) { - final boolean reschedule = arg2 == 1; - handleFinishedH(reschedule); - } else { - if (DEBUG) { - Slog.d(TAG, "Unrecognised callback: " + mRunningJob); - } - } + if (mVerb == VERB_STARTING) { + handleStartedLocked(reschedule); + } else if (mVerb == VERB_EXECUTING || + mVerb == VERB_STOPPING) { + handleFinishedLocked(reschedule); + } else { + if (DEBUG) { + Slog.d(TAG, "Unrecognised callback: " + mRunningJob); } } + } - void doCancel(int arg1) { - synchronized (mLock) { - if (mVerb == VERB_FINISHED) { - if (DEBUG) { - Slog.d(TAG, - "Trying to process cancel for torn-down context, ignoring."); - } - return; - } - mParams.setStopReason(arg1); - if (arg1 == JobParameters.REASON_PREEMPT) { - mPreferredUid = mRunningJob != null ? mRunningJob.getUid() : - NO_PREFERRED_UID; - } - handleCancelH(); + void doCancelLocked(int arg1) { + if (mVerb == VERB_FINISHED) { + if (DEBUG) { + Slog.d(TAG, + "Trying to process cancel for torn-down context, ignoring."); } - + return; + } + mParams.setStopReason(arg1); + if (arg1 == JobParameters.REASON_PREEMPT) { + mPreferredUid = mRunningJob != null ? mRunningJob.getUid() : + NO_PREFERRED_UID; } + handleCancelLocked(); + } - /** Start the job on the service. */ - private void handleServiceBoundH() { + /** Start the job on the service. */ + private void handleServiceBoundLocked() { + if (DEBUG) { + Slog.d(TAG, "handleServiceBound for " + mRunningJob.toShortString()); + } + if (mVerb != VERB_BINDING) { + Slog.e(TAG, "Sending onStartJob for a job that isn't pending. " + + VERB_STRINGS[mVerb]); + closeAndCleanupJobLocked(false /* reschedule */); + return; + } + if (mCancelled) { if (DEBUG) { - Slog.d(TAG, "MSG_SERVICE_BOUND for " + mRunningJob.toShortString()); - } - if (mVerb != VERB_BINDING) { - Slog.e(TAG, "Sending onStartJob for a job that isn't pending. " - + VERB_STRINGS[mVerb]); - closeAndCleanupJobH(false /* reschedule */); - return; - } - if (mCancelled.get()) { - if (DEBUG) { - Slog.d(TAG, "Job cancelled while waiting for bind to complete. " - + mRunningJob); - } - closeAndCleanupJobH(true /* reschedule */); - return; - } - try { - mVerb = VERB_STARTING; - scheduleOpTimeOutLocked(); - service.startJob(mParams); - } catch (Exception e) { - // We catch 'Exception' because client-app malice or bugs might induce a wide - // range of possible exception-throw outcomes from startJob() and its handling - // of the client's ParcelableBundle extras. - Slog.e(TAG, "Error sending onStart message to '" + - mRunningJob.getServiceComponent().getShortClassName() + "' ", e); + Slog.d(TAG, "Job cancelled while waiting for bind to complete. " + + mRunningJob); } + closeAndCleanupJobLocked(true /* reschedule */); + return; } + try { + mVerb = VERB_STARTING; + scheduleOpTimeOutLocked(); + service.startJob(mParams); + } catch (Exception e) { + // We catch 'Exception' because client-app malice or bugs might induce a wide + // range of possible exception-throw outcomes from startJob() and its handling + // of the client's ParcelableBundle extras. + Slog.e(TAG, "Error sending onStart message to '" + + mRunningJob.getServiceComponent().getShortClassName() + "' ", e); + } + } - /** - * State behaviours. - * VERB_STARTING -> Successful start, change job to VERB_EXECUTING and post timeout. - * _PENDING -> Error - * _EXECUTING -> Error - * _STOPPING -> Error - */ - private void handleStartedH(boolean workOngoing) { - switch (mVerb) { - case VERB_STARTING: - mVerb = VERB_EXECUTING; - if (!workOngoing) { - // Job is finished already so fast-forward to handleFinished. - handleFinishedH(false); - return; - } - if (mCancelled.get()) { - if (DEBUG) { - Slog.d(TAG, "Job cancelled while waiting for onStartJob to complete."); - } - // Cancelled *while* waiting for acknowledgeStartMessage from client. - handleCancelH(); - return; + /** + * State behaviours. + * VERB_STARTING -> Successful start, change job to VERB_EXECUTING and post timeout. + * _PENDING -> Error + * _EXECUTING -> Error + * _STOPPING -> Error + */ + private void handleStartedLocked(boolean workOngoing) { + switch (mVerb) { + case VERB_STARTING: + mVerb = VERB_EXECUTING; + if (!workOngoing) { + // Job is finished already so fast-forward to handleFinished. + handleFinishedLocked(false); + return; + } + if (mCancelled) { + if (DEBUG) { + Slog.d(TAG, "Job cancelled while waiting for onStartJob to complete."); } - scheduleOpTimeOutLocked(); - break; - default: - Slog.e(TAG, "Handling started job but job wasn't starting! Was " - + VERB_STRINGS[mVerb] + "."); + // Cancelled *while* waiting for acknowledgeStartMessage from client. + handleCancelLocked(); return; - } + } + scheduleOpTimeOutLocked(); + break; + default: + Slog.e(TAG, "Handling started job but job wasn't starting! Was " + + VERB_STRINGS[mVerb] + "."); + return; } + } - /** - * VERB_EXECUTING -> Client called jobFinished(), clean up and notify done. - * _STOPPING -> Successful finish, clean up and notify done. - * _STARTING -> Error - * _PENDING -> Error - */ - private void handleFinishedH(boolean reschedule) { - switch (mVerb) { - case VERB_EXECUTING: - case VERB_STOPPING: - closeAndCleanupJobH(reschedule); - break; - default: - Slog.e(TAG, "Got an execution complete message for a job that wasn't being" + - "executed. Was " + VERB_STRINGS[mVerb] + "."); - } + /** + * VERB_EXECUTING -> Client called jobFinished(), clean up and notify done. + * _STOPPING -> Successful finish, clean up and notify done. + * _STARTING -> Error + * _PENDING -> Error + */ + private void handleFinishedLocked(boolean reschedule) { + switch (mVerb) { + case VERB_EXECUTING: + case VERB_STOPPING: + closeAndCleanupJobLocked(reschedule); + break; + default: + Slog.e(TAG, "Got an execution complete message for a job that wasn't being" + + "executed. Was " + VERB_STRINGS[mVerb] + "."); } + } - /** - * A job can be in various states when a cancel request comes in: - * VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for - * {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)} - * _STARTING -> Mark as cancelled and wait for - * {@link JobServiceContext#acknowledgeStartMessage(int, boolean)} - * _EXECUTING -> call {@link #sendStopMessageH}}, but only if there are no callbacks - * in the message queue. - * _ENDING -> No point in doing anything here, so we ignore. - */ - private void handleCancelH() { - if (JobSchedulerService.DEBUG) { - Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " " - + VERB_STRINGS[mVerb]); - } - switch (mVerb) { - case VERB_BINDING: - case VERB_STARTING: - mCancelled.set(true); - break; - case VERB_EXECUTING: - if (hasMessages(MSG_CALLBACK)) { - // If the client has called jobFinished, ignore this cancel. - return; - } - sendStopMessageH(); - break; - case VERB_STOPPING: - // Nada. - break; - default: - Slog.e(TAG, "Cancelling a job without a valid verb: " + mVerb); - break; - } + /** + * A job can be in various states when a cancel request comes in: + * VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for + * {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)} + * _STARTING -> Mark as cancelled and wait for + * {@link JobServiceContext#acknowledgeStartMessage(int, boolean)} + * _EXECUTING -> call {@link #sendStopMessageLocked}}, but only if there are no callbacks + * in the message queue. + * _ENDING -> No point in doing anything here, so we ignore. + */ + private void handleCancelLocked() { + if (JobSchedulerService.DEBUG) { + Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " " + + VERB_STRINGS[mVerb]); } + switch (mVerb) { + case VERB_BINDING: + case VERB_STARTING: + mCancelled = true; + break; + case VERB_EXECUTING: + sendStopMessageLocked(); + break; + case VERB_STOPPING: + // Nada. + break; + default: + Slog.e(TAG, "Cancelling a job without a valid verb: " + mVerb); + break; + } + } - /** Process MSG_TIMEOUT here. */ - private void handleOpTimeoutH() { - switch (mVerb) { - case VERB_BINDING: - Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() + - ", dropping."); - closeAndCleanupJobH(false /* needsReschedule */); - break; - case VERB_STARTING: - // Client unresponsive - wedged or failed to respond in time. We don't really - // know what happened so let's log it and notify the JobScheduler - // FINISHED/NO-RETRY. - Slog.e(TAG, "No response from client for onStartJob '" + - mRunningJob.toShortString()); - closeAndCleanupJobH(false /* needsReschedule */); - break; - case VERB_STOPPING: - // At least we got somewhere, so fail but ask the JobScheduler to reschedule. - Slog.e(TAG, "No response from client for onStopJob, '" + - mRunningJob.toShortString()); - closeAndCleanupJobH(true /* needsReschedule */); - break; - case VERB_EXECUTING: - // Not an error - client ran out of time. - Slog.i(TAG, "Client timed out while executing (no jobFinished received)." + - " sending onStop. " + mRunningJob.toShortString()); - mParams.setStopReason(JobParameters.REASON_TIMEOUT); - sendStopMessageH(); - break; - default: - Slog.e(TAG, "Handling timeout for an invalid job state: " + - mRunningJob.toShortString() + ", dropping."); - closeAndCleanupJobH(false /* needsReschedule */); - } + /** Process MSG_TIMEOUT here. */ + private void handleOpTimeoutLocked() { + switch (mVerb) { + case VERB_BINDING: + Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() + + ", dropping."); + closeAndCleanupJobLocked(false /* needsReschedule */); + break; + case VERB_STARTING: + // Client unresponsive - wedged or failed to respond in time. We don't really + // know what happened so let's log it and notify the JobScheduler + // FINISHED/NO-RETRY. + Slog.e(TAG, "No response from client for onStartJob '" + + mRunningJob.toShortString()); + closeAndCleanupJobLocked(false /* needsReschedule */); + break; + case VERB_STOPPING: + // At least we got somewhere, so fail but ask the JobScheduler to reschedule. + Slog.e(TAG, "No response from client for onStopJob, '" + + mRunningJob.toShortString()); + closeAndCleanupJobLocked(true /* needsReschedule */); + break; + case VERB_EXECUTING: + // Not an error - client ran out of time. + Slog.i(TAG, "Client timed out while executing (no jobFinished received)." + + " sending onStop. " + mRunningJob.toShortString()); + mParams.setStopReason(JobParameters.REASON_TIMEOUT); + sendStopMessageLocked(); + break; + default: + Slog.e(TAG, "Handling timeout for an invalid job state: " + + mRunningJob.toShortString() + ", dropping."); + closeAndCleanupJobLocked(false /* needsReschedule */); } + } - /** - * Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING -> - * VERB_STOPPING. - */ - private void sendStopMessageH() { - removeOpTimeOutLocked(); - if (mVerb != VERB_EXECUTING) { - Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob); - closeAndCleanupJobH(false /* reschedule */); - return; - } - try { - mVerb = VERB_STOPPING; - scheduleOpTimeOutLocked(); - service.stopJob(mParams); - } catch (RemoteException e) { - Slog.e(TAG, "Error sending onStopJob to client.", e); - // The job's host app apparently crashed during the job, so we should reschedule. - closeAndCleanupJobH(true /* reschedule */); - } + /** + * Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING -> + * VERB_STOPPING. + */ + private void sendStopMessageLocked() { + removeOpTimeOutLocked(); + if (mVerb != VERB_EXECUTING) { + Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob); + closeAndCleanupJobLocked(false /* reschedule */); + return; + } + try { + mVerb = VERB_STOPPING; + scheduleOpTimeOutLocked(); + service.stopJob(mParams); + } catch (RemoteException e) { + Slog.e(TAG, "Error sending onStopJob to client.", e); + // The job's host app apparently crashed during the job, so we should reschedule. + closeAndCleanupJobLocked(true /* reschedule */); } + } - /** - * The provided job has finished, either by calling - * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)} - * or from acknowledging the stop message we sent. Either way, we're done tracking it and - * we want to clean up internally. - */ - private void closeAndCleanupJobH(boolean reschedule) { - final JobStatus completedJob; - synchronized (mLock) { - if (mVerb == VERB_FINISHED) { - return; - } - completedJob = mRunningJob; - mJobPackageTracker.noteInactive(completedJob); - try { - mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), - mRunningJob.getSourceUid()); - } catch (RemoteException e) { - // Whatever. - } - if (mWakeLock != null) { - mWakeLock.release(); - } - mContext.unbindService(JobServiceContext.this); - mWakeLock = null; - mRunningJob = null; - mParams = null; - mVerb = VERB_FINISHED; - mCancelled.set(false); - service = null; - mAvailable = true; - removeOpTimeOutLocked(); - removeMessages(MSG_CALLBACK); - removeMessages(MSG_SERVICE_BOUND); - removeMessages(MSG_CANCEL); - removeMessages(MSG_SHUTDOWN_EXECUTION); - mCompletedListener.onJobCompletedLocked(completedJob, reschedule); - } + /** + * The provided job has finished, either by calling + * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)} + * or from acknowledging the stop message we sent. Either way, we're done tracking it and + * we want to clean up internally. + */ + private void closeAndCleanupJobLocked(boolean reschedule) { + final JobStatus completedJob; + if (mVerb == VERB_FINISHED) { + return; } + completedJob = mRunningJob; + mJobPackageTracker.noteInactive(completedJob); + try { + mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), + mRunningJob.getSourceUid()); + } catch (RemoteException e) { + // Whatever. + } + if (mWakeLock != null) { + mWakeLock.release(); + } + mContext.unbindService(JobServiceContext.this); + mWakeLock = null; + mRunningJob = null; + mParams = null; + mVerb = VERB_FINISHED; + mCancelled = false; + service = null; + mAvailable = true; + removeOpTimeOutLocked(); + mCompletedListener.onJobCompletedLocked(completedJob, reschedule); } /** 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 e8cc078b7eb1..1ab66b9abb7f 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -26,7 +26,6 @@ import android.content.ContentProvider; import android.content.Intent; import android.net.Uri; import android.os.Binder; -import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -35,6 +34,8 @@ import android.util.ArraySet; import android.util.Slog; import android.util.TimeUtils; +import com.android.server.job.GrantedUriPermissions; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -103,7 +104,7 @@ public final class JobStatus { final String tag; - private IBinder permissionOwner; + private GrantedUriPermissions uriPerms; private boolean prepared; /** @@ -284,12 +285,17 @@ public final class JobStatus { earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis); } - public void enqueueWorkLocked(JobWorkItem work) { + public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) { if (pendingWork == null) { pendingWork = new ArrayList<>(); } work.setWorkId(nextPendingWorkId); nextPendingWorkId++; + if (work.getIntent() != null + && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) { + work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid, + sourcePackageName, sourceUserId, toShortString())); + } pendingWork.add(work); } @@ -311,12 +317,20 @@ public final class JobStatus { return executingWork != null && executingWork.size() > 0; } - public boolean completeWorkLocked(int workId) { + private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) { + if (work.getGrants() != null) { + ((GrantedUriPermissions)work.getGrants()).revoke(am); + } + } + + public boolean completeWorkLocked(IActivityManager am, int workId) { if (executingWork != null) { final int N = executingWork.size(); for (int i = 0; i < N; i++) { - if (executingWork.get(i).getWorkId() == workId) { + JobWorkItem work = executingWork.get(i); + if (work.getWorkId() == workId) { executingWork.remove(i); + ungrantWorkItem(am, work); return true; } } @@ -324,15 +338,36 @@ public final class JobStatus { return false; } - public void stopTrackingJobLocked(JobStatus incomingJob) { + private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) { + if (list != null) { + final int N = list.size(); + for (int i = 0; i < N; i++) { + ungrantWorkItem(am, list.get(i)); + } + } + } + + public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) { if (incomingJob != null) { - // We are replacing with a new job -- transfer the work! - incomingJob.pendingWork = pendingWork; + // We are replacing with a new job -- transfer the work! We do any executing + // work first, since that was originally at the front of the pending work. + if (executingWork != null && executingWork.size() > 0) { + incomingJob.pendingWork = executingWork; + } + if (incomingJob.pendingWork == null) { + incomingJob.pendingWork = pendingWork; + } else if (pendingWork != null && pendingWork.size() > 0) { + incomingJob.pendingWork.addAll(pendingWork); + } pendingWork = null; + executingWork = null; incomingJob.nextPendingWorkId = nextPendingWorkId; } else { // We are completely stopping the job... need to clean up work. - // XXX remove perms when that is impl. + ungrantWorkList(am, pendingWork); + pendingWork = null; + ungrantWorkList(am, executingWork); + executingWork = null; } } @@ -344,10 +379,8 @@ public final class JobStatus { prepared = true; final ClipData clip = job.getClipData(); if (clip != null) { - final int N = clip.getItemCount(); - for (int i = 0; i < N; i++) { - grantItemLocked(am, clip.getItemAt(i), sourceUid, sourcePackageName, sourceUserId); - } + uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName, + sourceUserId, job.getClipGrantFlags(), toShortString()); } } @@ -357,14 +390,9 @@ public final class JobStatus { return; } prepared = false; - if (permissionOwner != null) { - final ClipData clip = job.getClipData(); - if (clip != null) { - final int N = clip.getItemCount(); - for (int i = 0; i < N; i++) { - revokeItemLocked(am, clip.getItemAt(i)); - } - } + if (uriPerms != null) { + uriPerms.revoke(am); + uriPerms = null; } } @@ -372,57 +400,6 @@ public final class JobStatus { return prepared; } - private final void grantUriLocked(IActivityManager am, Uri uri, int sourceUid, - String targetPackage, int targetUserId) { - try { - int sourceUserId = ContentProvider.getUserIdFromUri(uri, - UserHandle.getUserId(sourceUid)); - uri = ContentProvider.getUriWithoutUserId(uri); - if (permissionOwner == null) { - permissionOwner = am.newUriPermissionOwner("job: " + toShortString()); - } - am.grantUriPermissionFromOwner(permissionOwner, sourceUid, targetPackage, - uri, job.getClipGrantFlags(), sourceUserId, targetUserId); - } catch (RemoteException e) { - Slog.e("JobScheduler", "AM dead"); - } - } - - private final void grantItemLocked(IActivityManager am, ClipData.Item item, int sourceUid, - String targetPackage, int targetUserId) { - if (item.getUri() != null) { - grantUriLocked(am, item.getUri(), sourceUid, targetPackage, targetUserId); - } - Intent intent = item.getIntent(); - if (intent != null && intent.getData() != null) { - grantUriLocked(am, intent.getData(), sourceUid, targetPackage, targetUserId); - } - } - - private final void revokeUriLocked(IActivityManager am, Uri uri) { - int userId = ContentProvider.getUserIdFromUri(uri, - UserHandle.getUserId(Binder.getCallingUid())); - long ident = Binder.clearCallingIdentity(); - try { - uri = ContentProvider.getUriWithoutUserId(uri); - am.revokeUriPermissionFromOwner(permissionOwner, uri, - job.getClipGrantFlags(), userId); - } catch (RemoteException e) { - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - private final void revokeItemLocked(IActivityManager am, ClipData.Item item) { - if (item.getUri() != null) { - revokeUriLocked(am, item.getUri()); - } - Intent intent = item.getIntent(); - if (intent != null && intent.getData() != null) { - revokeUriLocked(am, intent.getData()); - } - } - public JobInfo getJob() { return job; } @@ -833,6 +810,15 @@ public final class JobStatus { } } + private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) { + pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #"); + pw.print(work.getWorkId()); pw.print(" "); pw.println(work.getIntent()); + if (work.getGrants() != null) { + pw.print(prefix); pw.println(" URI grants:"); + ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " "); + } + } + // Dumpsys infrastructure public void dump(PrintWriter pw, String prefix, boolean full) { pw.print(prefix); UserHandle.formatUid(pw, callingUid); @@ -898,6 +884,10 @@ public final class JobStatus { job.getClipData().toShortString(b); pw.println(b); } + if (uriPerms != null) { + pw.print(prefix); pw.println(" Granted URI permissions:"); + uriPerms.dump(pw, prefix + " "); + } if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) { pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType()); } @@ -950,17 +940,13 @@ public final class JobStatus { if (pendingWork != null && pendingWork.size() > 0) { pw.print(prefix); pw.println("Pending work:"); for (int i = 0; i < pendingWork.size(); i++) { - JobWorkItem work = pendingWork.get(i); - pw.print(prefix); pw.print(" #"); pw.print(i); pw.print(": #"); - pw.print(work.getWorkId()); pw.print(" "); pw.println(work.getIntent()); + dumpJobWorkItem(pw, prefix, pendingWork.get(i), i); } } if (executingWork != null && executingWork.size() > 0) { pw.print(prefix); pw.println("Executing work:"); for (int i = 0; i < executingWork.size(); i++) { - JobWorkItem work = executingWork.get(i); - pw.print(prefix); pw.print(" #"); pw.print(i); pw.print(": #"); - pw.print(work.getWorkId()); pw.print(" "); pw.println(work.getIntent()); + dumpJobWorkItem(pw, prefix, executingWork.get(i), i); } } pw.print(prefix); pw.print("Earliest run time: "); diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 53a8092fa558..ee348cf71c88 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -101,8 +101,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private ParceledListSlice mQueue; private CharSequence mQueueTitle; private int mRatingType; - private int mRepeatMode; - private boolean mShuffleModeEnabled; // End TransportPerformer fields // Volume handling fields @@ -622,47 +620,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } - private void pushRepeatModeUpdate() { - synchronized (mLock) { - if (mDestroyed) { - return; - } - for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) { - ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i); - try { - holder.mCallback.onRepeatModeChanged(mRepeatMode); - } catch (DeadObjectException e) { - mControllerCallbackHolders.remove(i); - logCallbackException("Removed dead callback in pushRepeatModeUpdate", - holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushRepeatModeUpdate", holder, e); - } - } - } - } - - private void pushShuffleModeUpdate() { - synchronized (mLock) { - if (mDestroyed) { - return; - } - for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) { - ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i); - try { - holder.mCallback.onShuffleModeChanged(mShuffleModeEnabled); - } catch (DeadObjectException e) { - mControllerCallbackHolders.remove(i); - logCallbackException("Removed dead callback in pushShuffleModeUpdate", - holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushShuffleModeUpdate", - holder, e); - } - } - } - } - private void pushSessionDestroyed() { synchronized (mLock) { // This is the only method that may be (and can only be) called @@ -887,30 +844,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void setRepeatMode(int repeatMode) { - boolean changed; - synchronized (mLock) { - changed = mRepeatMode != repeatMode; - mRepeatMode = repeatMode; - } - if (changed) { - mHandler.post(MessageHandler.MSG_UPDATE_REPEAT_MODE); - } - } - - @Override - public void setShuffleModeEnabled(boolean enabled) { - boolean changed; - synchronized (mLock) { - changed = mShuffleModeEnabled != enabled; - mShuffleModeEnabled = enabled; - } - if (changed) { - mHandler.post(MessageHandler.MSG_UPDATE_SHUFFLE_MODE); - } - } - - @Override public void setCurrentVolume(int volume) { mCurrentVolume = volume; mHandler.post(MessageHandler.MSG_UPDATE_VOLUME); @@ -1126,54 +1059,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } - public void repeatMode(int repeatMode) { - try { - mCb.onRepeatMode(repeatMode); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in repeatMode.", e); - } - } - - public void shuffleMode(boolean enabled) { - try { - mCb.onShuffleMode(enabled); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in shuffleMode.", e); - } - } - - public void addQueueItem(MediaDescription description) { - try { - mCb.onAddQueueItem(description); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in addQueueItem.", e); - } - } - - public void addQueueItemAt(MediaDescription description, int index) { - try { - mCb.onAddQueueItemAt(description, index); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in addQueueItemAt.", e); - } - } - - public void removeQueueItem(MediaDescription description) { - try { - mCb.onRemoveQueueItem(description); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in removeQueueItem.", e); - } - } - - public void removeQueueItemAt(int index) { - try { - mCb.onRemoveQueueItemAt(index); - } catch (RemoteException e) { - Slog.e(TAG, "Remote failure in removeQueueItem.", e); - } - } - public void adjustVolume(int direction) { try { mCb.onAdjustVolume(direction); @@ -1410,25 +1295,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void repeatMode(int repeatMode) { - updateCallingPackage(); - mSessionCb.repeatMode(repeatMode); - } - - @Override - public void shuffleMode(boolean enabled) throws RemoteException { - updateCallingPackage(); - mSessionCb.shuffleMode(enabled); - } - - - @Override public void sendCustomAction(String action, Bundle args) throws RemoteException { updateCallingPackage(); mSessionCb.sendCustomAction(action, args); } + @Override public MediaMetadata getMetadata() { synchronized (mLock) { @@ -1449,30 +1322,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void addQueueItem(MediaDescription description) { - updateCallingPackage(); - mSessionCb.addQueueItem(description); - } - - @Override - public void addQueueItemAt(MediaDescription description, int index) { - updateCallingPackage(); - mSessionCb.addQueueItemAt(description, index); - } - - @Override - public void removeQueueItem(MediaDescription description) { - updateCallingPackage(); - mSessionCb.removeQueueItem(description); - } - - @Override - public void removeQueueItemAt(int index) { - updateCallingPackage(); - mSessionCb.removeQueueItemAt(index); - } - - @Override public CharSequence getQueueTitle() { return mQueueTitle; } @@ -1490,16 +1339,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public int getRepeatMode() { - return mRepeatMode; - } - - @Override - public boolean isShuffleModeEnabled() { - return mShuffleModeEnabled; - } - - @Override public boolean isTransportControlEnabled() { return MediaSessionRecord.this.isTransportControlEnabled(); } @@ -1524,9 +1363,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private static final int MSG_SEND_EVENT = 6; private static final int MSG_UPDATE_SESSION_STATE = 7; private static final int MSG_UPDATE_VOLUME = 8; - private static final int MSG_UPDATE_REPEAT_MODE = 9; - private static final int MSG_UPDATE_SHUFFLE_MODE = 10; - private static final int MSG_DESTROYED = 11; + private static final int MSG_DESTROYED = 9; public MessageHandler(Looper looper) { super(looper); @@ -1558,12 +1395,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { case MSG_UPDATE_VOLUME: pushVolumeUpdate(); break; - case MSG_UPDATE_REPEAT_MODE: - pushRepeatModeUpdate(); - break; - case MSG_UPDATE_SHUFFLE_MODE: - pushShuffleModeUpdate(); - break; case MSG_DESTROYED: pushSessionDestroyed(); } diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index b0d8adcc122e..2f82915a459b 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -23,6 +23,7 @@ import android.os.Debug; import android.os.UserHandle; import android.util.IntArray; import android.util.Log; +import android.util.SparseArray; import java.io.PrintWriter; import java.util.ArrayList; @@ -38,7 +39,7 @@ class MediaSessionStack { private static final String TAG = "MediaSessionStack"; /** - * Listens the change in the media button session. + * Listen the change in the media button session. */ interface OnMediaButtonSessionChangedListener { /** @@ -85,7 +86,12 @@ class MediaSessionStack { private MediaSessionRecord mCachedDefault; private MediaSessionRecord mCachedVolumeDefault; - private ArrayList<MediaSessionRecord> mCachedActiveList; + + /** + * Cache the result of the {@link #getActiveSessions} per user. + */ + private final SparseArray<ArrayList<MediaSessionRecord>> mCachedActiveLists = + new SparseArray<>(); MediaSessionStack(AudioPlaybackMonitor monitor, OnMediaButtonSessionChangedListener listener) { mAudioPlaybackMonitor = monitor; @@ -99,7 +105,7 @@ class MediaSessionStack { */ public void addSession(MediaSessionRecord record) { mSessions.add(record); - clearCache(); + clearCache(record.getUserId()); // Update the media button session. // The added session could be the session from the package with the audio playback. @@ -119,7 +125,7 @@ class MediaSessionStack { // in the media button session app. onMediaSessionChangeInMediaButtonSessionApp(); } - clearCache(); + clearCache(record.getUserId()); } /** @@ -140,7 +146,7 @@ class MediaSessionStack { if (shouldUpdatePriority(oldState, newState)) { mSessions.remove(record); mSessions.add(0, record); - clearCache(); + clearCache(record.getUserId()); } else if (!MediaSession.isActiveState(newState)) { // Just clear the volume cache when a state goes inactive mCachedVolumeDefault = null; @@ -163,7 +169,7 @@ class MediaSessionStack { public void onSessionStateChange(MediaSessionRecord record) { // For now just clear the cache. Eventually we'll selectively clear // depending on what changed. - clearCache(); + clearCache(record.getUserId()); } /** @@ -245,14 +251,17 @@ class MediaSessionStack { * Get the current priority sorted list of active sessions. The most * important session is at index 0 and the least important at size - 1. * - * @param userId The user to check. + * @param userId The user to check. It can be {@link UserHandle#USER_ALL} to get all sessions + * for all users in this {@link MediaSessionStack}. * @return All the active sessions in priority order. */ public ArrayList<MediaSessionRecord> getActiveSessions(int userId) { - if (mCachedActiveList == null) { - mCachedActiveList = getPriorityList(true, userId); + ArrayList<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId); + if (cachedActiveList == null) { + cachedActiveList = getPriorityList(true, userId); + mCachedActiveLists.put(userId, cachedActiveList); } - return mCachedActiveList; + return cachedActiveList; } /** @@ -382,9 +391,12 @@ class MediaSessionStack { return false; } - private void clearCache() { + private void clearCache(int userId) { mCachedDefault = null; mCachedVolumeDefault = null; - mCachedActiveList = null; + mCachedActiveLists.remove(userId); + // mCachedActiveLists may also include the list of sessions for UserHandle.USER_ALL, + // so they also need to be cleared. + mCachedActiveLists.remove(UserHandle.USER_ALL); } } diff --git a/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java b/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java index ce976d29216b..acedafc4025c 100644 --- a/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java +++ b/services/core/java/com/android/server/notification/GlobalSortKeyComparator.java @@ -15,19 +15,25 @@ */ package com.android.server.notification; +import android.util.Slog; + import java.util.Comparator; /** * Sorts notifications by their global sort key. */ public class GlobalSortKeyComparator implements Comparator<NotificationRecord> { + private final static String TAG = "GlobalSortComp"; + @Override public int compare(NotificationRecord left, NotificationRecord right) { if (left.getGlobalSortKey() == null) { - throw new IllegalStateException("Missing left global sort key: " + left); + Slog.wtf(TAG, "Missing left global sort key: " + left); + return 1; } if (right.getGlobalSortKey() == null) { - throw new IllegalStateException("Missing right global sort key: " + right); + Slog.wtf(TAG, "Missing right global sort key: " + right); + return -1; } return left.getGlobalSortKey().compareTo(right.getGlobalSortKey()); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f334ba41bdf1..8a6a940e6669 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -97,6 +97,7 @@ import android.media.AudioManagerInternal; import android.media.IRingtonePlayer; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -1322,7 +1323,8 @@ public class NotificationManagerService extends SystemService { if (!fromListener) { mListeners.notifyNotificationChannelChanged( - pkg, modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); + pkg, UserHandle.getUserHandleForUid(uid), + modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); } synchronized (mNotificationLock) { @@ -1647,7 +1649,8 @@ public class NotificationManagerService extends SystemService { Preconditions.checkNotNull(group, "group in list is null"); mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true /* fromTargetApp */); - mListeners.notifyNotificationChannelGroupChanged(pkg, group, + mListeners.notifyNotificationChannelGroupChanged(pkg, + UserHandle.of(UserHandle.getCallingUserId()), group, NOTIFICATION_CHANNEL_OR_GROUP_ADDED); } savePolicyFile(); @@ -1663,6 +1666,7 @@ public class NotificationManagerService extends SystemService { mRankingHelper.createNotificationChannel(pkg, uid, channel, true /* fromTargetApp */); mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(uid), mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false), NOTIFICATION_CHANNEL_OR_GROUP_ADDED); } @@ -1708,6 +1712,7 @@ public class NotificationManagerService extends SystemService { UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(callingUid), mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true), NOTIFICATION_CHANNEL_OR_GROUP_DELETED); savePolicyFile(); @@ -1737,11 +1742,14 @@ public class NotificationManagerService extends SystemService { true, UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); - mListeners.notifyNotificationChannelChanged(pkg, deletedChannel, + mListeners.notifyNotificationChannelChanged(pkg, + UserHandle.getUserHandleForUid(callingUid), + deletedChannel, NOTIFICATION_CHANNEL_OR_GROUP_DELETED); } mListeners.notifyNotificationChannelGroupChanged( - pkg, groupToDelete, NOTIFICATION_CHANNEL_OR_GROUP_DELETED); + pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete, + NOTIFICATION_CHANNEL_OR_GROUP_DELETED); savePolicyFile(); } } @@ -1866,10 +1874,9 @@ public class NotificationManagerService extends SystemService { int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), incomingUserId, true, false, "getAppActiveNotifications", pkg); - final ArrayMap<String, StatusBarNotification> map - = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); - synchronized (mNotificationLock) { + final ArrayMap<String, StatusBarNotification> map + = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size()); final int N = mNotificationList.size(); for (int i = 0; i < N; i++) { StatusBarNotification sbn = sanitizeSbn(pkg, userId, @@ -1892,11 +1899,10 @@ public class NotificationManagerService extends SystemService { map.put(sbn.getKey(), sbn); // pending update overwrites existing post here } } + final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); + list.addAll(map.values()); + return new ParceledListSlice<StatusBarNotification>(list); } - - final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size()); - list.addAll(map.values()); - return new ParceledListSlice<StatusBarNotification>(list); } private StatusBarNotification sanitizeSbn(String pkg, int userId, @@ -2028,8 +2034,10 @@ public class NotificationManagerService extends SystemService { long identity = Binder.clearCallingIdentity(); try { // allow bound services to disable themselves - final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - info.getOwner().setComponentState(info.component, false); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + info.getOwner().setComponentState(info.component, false); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2093,8 +2101,10 @@ public class NotificationManagerService extends SystemService { String key, String snoozeCriterionId) { long identity = Binder.clearCallingIdentity(); try { - final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2110,8 +2120,10 @@ public class NotificationManagerService extends SystemService { long duration) { long identity = Binder.clearCallingIdentity(); try { - final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - snoozeNotificationInt(key, duration, null, info); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + snoozeNotificationInt(key, duration, null, info); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2126,9 +2138,11 @@ public class NotificationManagerService extends SystemService { public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) { long identity = Binder.clearCallingIdentity(); try { - final ManagedServiceInfo info = - mNotificationAssistants.checkServiceTokenLocked(token); - unsnoozeNotificationInt(key, info); + synchronized (mNotificationLock) { + final ManagedServiceInfo info = + mNotificationAssistants.checkServiceTokenLocked(token); + unsnoozeNotificationInt(key, info); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -2691,43 +2705,62 @@ public class NotificationManagerService extends SystemService { @Override public void updateNotificationChannelFromPrivilegedListener(INotificationListener token, - String pkg, NotificationChannel channel) throws RemoteException { + String pkg, UserHandle user, NotificationChannel channel) throws RemoteException { Preconditions.checkNotNull(channel); + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); - } - - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - updateNotificationChannelInt(pkg, uid, channel, true); + verifyPrivilegedListener(token, user); + updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true); } @Override public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener( - INotificationListener token, String pkg) throws RemoteException { - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - if (!hasCompanionDevice(info)) { - throw new SecurityException(info + " does not have access"); - } + INotificationListener token, String pkg, UserHandle user) throws RemoteException { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); + verifyPrivilegedListener(token, user); - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */); + return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user), + false /* includeDeleted */); } @Override public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsFromPrivilegedListener( - INotificationListener token, String pkg) throws RemoteException { - ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + INotificationListener token, String pkg, UserHandle user) throws RemoteException { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(user); + verifyPrivilegedListener(token, user); + + List<NotificationChannelGroup> groups = new ArrayList<>(); + groups.addAll(mRankingHelper.getNotificationChannelGroups( + pkg, getUidForPackageAndUser(pkg, user))); + return new ParceledListSlice<>(groups); + } + + private void verifyPrivilegedListener(INotificationListener token, UserHandle user) { + ManagedServiceInfo info; + synchronized (mNotificationLock) { + info = mListeners.checkServiceTokenLocked(token); + } if (!hasCompanionDevice(info)) { throw new SecurityException(info + " does not have access"); } + if (!info.enabledAndUserMatches(user.getIdentifier())) { + throw new SecurityException(info + " does not have access"); + } + } - List<NotificationChannelGroup> groups = new ArrayList<>(); - int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); - groups.addAll(mRankingHelper.getNotificationChannelGroups(pkg, uid)); - return new ParceledListSlice<>(groups); + private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException { + int uid = 0; + long identity = Binder.clearCallingIdentity(); + try { + uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier()); + } finally { + Binder.restoreCallingIdentity(identity); + } + return uid; } }; @@ -3075,8 +3108,10 @@ public class NotificationManagerService extends SystemService { @Override public void run() { synchronized (mNotificationLock) { - removeForegroundServiceFlagByListLocked(mEnqueuedNotifications, pkg, notificationId, userId); - removeForegroundServiceFlagByListLocked(mNotificationList, pkg, notificationId, userId); + removeForegroundServiceFlagByListLocked( + mEnqueuedNotifications, pkg, notificationId, userId); + removeForegroundServiceFlagByListLocked( + mNotificationList, pkg, notificationId, userId); } } }); @@ -3162,16 +3197,16 @@ public class NotificationManagerService extends SystemService { // STOPSHIP TODO: should throw instead of logging or toasting. // throw new IllegalArgumentException(noChannelStr); Log.e(TAG, noChannelStr); - - final String noChannelToastStr = - "Developer warning for package \"" + pkg + "\"\n" + + doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" + "Failed to post notification on channel \"" + channelId + "\"\n" + - "See log for more details"; - Toast noChannelToast = - Toast.makeText(getContext(), noChannelToastStr, Toast.LENGTH_LONG); - noChannelToast.show(); + "See log for more details"); return; + } else if (channelId == null && shouldWarnUseChannels(pkg, notificationUid)) { + // STOPSHIP TODO: remove once default channel is removed for all apps that target O. + doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" + + "Posted notification should specify a channel"); } + final StatusBarNotification n = new StatusBarNotification( pkg, opPkg, id, tag, notificationUid, callingPid, notification, user, null, System.currentTimeMillis()); @@ -3203,6 +3238,30 @@ public class NotificationManagerService extends SystemService { idOut[0] = id; } + private void doDebugOnlyToast(CharSequence toastText) { + if (Build.IS_DEBUGGABLE) { + try { + Toast toast = Toast.makeText(getContext(), toastText, Toast.LENGTH_LONG); + toast.show(); + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to toast with text: " + toastText, e); + } + } + } + + // STOPSHIP - Remove once RankingHelper deletes default channel for all apps targeting O. + private boolean shouldWarnUseChannels(String pkg, int uid) { + try { + final int userId = UserHandle.getUserId(uid); + final ApplicationInfo applicationInfo = + mPackageManagerClient.getApplicationInfoAsUser(pkg, 0, userId); + return applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1; + } catch (NameNotFoundException e) { + Slog.e(TAG, e.toString()); + return false; + } + } + private int resolveNotificationUid(String opPackageName, int callingUid, int userId) { // The system can post notifications on behalf of any package it wants if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) { @@ -5019,7 +5078,7 @@ public class NotificationManagerService extends SystemService { } } - protected void notifyNotificationChannelChanged(final String pkg, + protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user, final NotificationChannel channel, final int modificationType) { if (channel == null) { return; @@ -5034,15 +5093,16 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyNotificationChannelChanged(serviceInfo, pkg, channel, - modificationType); + notifyNotificationChannelChanged( + serviceInfo, pkg, user, channel, modificationType); } }); } } - protected void notifyNotificationChannelGroupChanged(final String pkg, - final NotificationChannelGroup group, final int modificationType) { + protected void notifyNotificationChannelGroupChanged( + final String pkg, final UserHandle user, final NotificationChannelGroup group, + final int modificationType) { if (group == null) { return; } @@ -5056,8 +5116,8 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyNotificationChannelGroupChanged(serviceInfo, pkg, group, - modificationType); + notifyNotificationChannelGroupChanged( + serviceInfo, pkg, user, group, modificationType); } }); } @@ -5118,22 +5178,22 @@ public class NotificationManagerService extends SystemService { } void notifyNotificationChannelChanged(ManagedServiceInfo info, - final String pkg, final NotificationChannel channel, + final String pkg, final UserHandle user, final NotificationChannel channel, final int modificationType) { final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationChannelModification(pkg, channel, modificationType); + listener.onNotificationChannelModification(pkg, user, channel, modificationType); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex); } } private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info, - final String pkg, final NotificationChannelGroup group, + final String pkg, final UserHandle user, final NotificationChannelGroup group, final int modificationType) { final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationChannelGroupModification(pkg, group, modificationType); + listener.onNotificationChannelGroupModification(pkg, user, group, modificationType); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index b7d31735a728..b48fd5c75574 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -172,7 +172,7 @@ public final class NotificationRecord { final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0; if (useDefaultSound) { sound = Settings.System.DEFAULT_NOTIFICATION_URI; - } else if (n.sound != null) { + } else { sound = n.sound; } } diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 7b865429d0d7..2e4b49add05f 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -274,23 +274,56 @@ public class OtaDexoptService extends IOtaDexopt.Stub { // Intercept and collect dexopt requests final List<String> commands = new ArrayList<String>(); final Installer collectingInstaller = new Installer(mContext, true) { + /** + * Encode the dexopt command into a string. + * + * Note: If you have to change the signature of this function, increase the version + * number, and update the counterpart in + * frameworks/native/cmds/installd/otapreopt.cpp. + */ @Override public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, @Nullable String seInfo) throws InstallerException { - commands.add(buildCommand("dexopt", - apkPath, - uid, - pkgName, - instructionSet, - dexoptNeeded, - outputPath, - dexFlags, - compilerFilter, - volumeUuid, - sharedLibraries, - seInfo)); + final StringBuilder builder = new StringBuilder(); + + // The version. Right now it's 2. + builder.append("2 "); + + builder.append("dexopt"); + + encodeParameter(builder, apkPath); + encodeParameter(builder, uid); + encodeParameter(builder, pkgName); + encodeParameter(builder, instructionSet); + encodeParameter(builder, dexoptNeeded); + encodeParameter(builder, outputPath); + encodeParameter(builder, dexFlags); + encodeParameter(builder, compilerFilter); + encodeParameter(builder, volumeUuid); + encodeParameter(builder, sharedLibraries); + encodeParameter(builder, seInfo); + + commands.add(builder.toString()); + } + + /** + * Encode a parameter as necessary for the commands string. + */ + private void encodeParameter(StringBuilder builder, Object arg) { + builder.append(' '); + + if (arg == null) { + builder.append('!'); + } + + String txt = String.valueOf(arg); + if (txt.indexOf('\0') != -1 || txt.indexOf(' ') != -1 || "!".equals(txt)) { + throw new IllegalArgumentException( + "Invalid argument while executing " + arg); + } + builder.append(txt); } }; @@ -430,28 +463,4 @@ public class OtaDexoptService extends IOtaDexopt.Stub { super(installer, installLock, context, "*otadexopt*"); } } - - /** - * Cook up argument list in the format that {@code installd} expects. - */ - private static String buildCommand(Object... args) { - final StringBuilder builder = new StringBuilder(); - for (Object arg : args) { - String escaped; - if (arg == null) { - escaped = ""; - } else { - escaped = String.valueOf(arg); - } - if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) { - throw new IllegalArgumentException( - "Invalid argument while executing " + Arrays.toString(args)); - } - if (TextUtils.isEmpty(escaped)) { - escaped = "!"; - } - builder.append(' ').append(escaped); - } - return builder.toString(); - } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 650d2f69fc08..312c310428a5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -364,7 +364,8 @@ import java.util.concurrent.atomic.AtomicInteger; * $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases * </pre> */ -public class PackageManagerService extends IPackageManager.Stub { +public class PackageManagerService extends IPackageManager.Stub + implements PackageSender { static final String TAG = "PackageManager"; static final boolean DEBUG_SETTINGS = false; static final boolean DEBUG_PREFERRED = false; @@ -13083,7 +13084,7 @@ public class PackageManagerService extends IPackageManager.Stub { } }; - final void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, + public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, final int[] userIds) { mHandler.post(new Runnable() { @@ -13201,7 +13202,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (dcsUid > 0) { am.backgroundWhitelistUid(dcsUid); } - am.startService(null, intent, null, -1, null, false, mContext.getOpPackageName(), + am.startService(null, intent, null, false, mContext.getOpPackageName(), UserHandle.USER_SYSTEM); } catch (RemoteException e) { } @@ -13386,8 +13387,7 @@ public class PackageManagerService extends IPackageManager.Stub { sendPackageAddedForNewUsers(packageName, isSystem, pkgSetting.appId, userId); } - private void sendPackageAddedForNewUsers(String packageName, boolean isSystem, - int appId, int... userIds) { + public void sendPackageAddedForNewUsers(String packageName, boolean isSystem, int appId, int... userIds) { if (ArrayUtils.isEmpty(userIds)) { return; } @@ -13514,7 +13514,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting, int userId) { - final PackageRemovedInfo info = new PackageRemovedInfo(); + final PackageRemovedInfo info = new PackageRemovedInfo(this); info.removedPackage = packageName; info.removedUsers = new int[] {userId}; info.broadcastUsers = new int[] {userId}; @@ -16150,7 +16150,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Update what is removed - res.removedInfo = new PackageRemovedInfo(); + res.removedInfo = new PackageRemovedInfo(this); res.removedInfo.uid = oldPackage.applicationInfo.uid; res.removedInfo.removedPackage = oldPackage.packageName; res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null; @@ -16180,7 +16180,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } if (!childPackageUpdated) { - PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(); + PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this); childRemovedRes.removedPackage = childPkg.packageName; childRemovedRes.isUpdate = false; childRemovedRes.dataRemoved = true; @@ -16870,7 +16870,7 @@ public class PackageManagerService extends IPackageManager.Stub { sUserManager.getUserIds(), true); } if ((mPackages.containsKey(childPkg.packageName))) { - childRes.removedInfo = new PackageRemovedInfo(); + childRes.removedInfo = new PackageRemovedInfo(this); childRes.removedInfo.removedPackage = childPkg.packageName; } if (res.addedChildPackages == null) { @@ -17716,7 +17716,7 @@ public class PackageManagerService extends IPackageManager.Stub { * sending a broadcast if necessary */ private int deletePackageX(String packageName, int versionCode, int userId, int deleteFlags) { - final PackageRemovedInfo info = new PackageRemovedInfo(); + final PackageRemovedInfo info = new PackageRemovedInfo(this); final boolean res; final int removeUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0 @@ -17816,7 +17816,8 @@ public class PackageManagerService extends IPackageManager.Stub { return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; } - class PackageRemovedInfo { + static class PackageRemovedInfo { + final PackageSender packageSender; String removedPackage; int uid = -1; int removedAppId = -1; @@ -17834,6 +17835,10 @@ public class PackageManagerService extends IPackageManager.Stub { ArrayMap<String, PackageRemovedInfo> removedChildPackages; ArrayMap<String, PackageInstalledInfo> appearedChildPackages; + PackageRemovedInfo(PackageSender packageSender) { + this.packageSender = packageSender; + } + void sendPackageRemovedBroadcasts(boolean killApp) { sendPackageRemovedBroadcastInternal(killApp); final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0; @@ -17862,8 +17867,9 @@ public class PackageManagerService extends IPackageManager.Stub { ? appearedChildPackages.size() : 0; for (int i = 0; i < packageCount; i++) { PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i); - sendPackageAddedForNewUsers(installedInfo.name, true, - UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers); + packageSender.sendPackageAddedForNewUsers(installedInfo.name, + true, UserHandle.getAppId(installedInfo.uid), + installedInfo.newUsers); } } @@ -17871,12 +17877,12 @@ public class PackageManagerService extends IPackageManager.Stub { Bundle extras = new Bundle(2); extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_REPLACING, true); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, - extras, 0, null, null, null); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage, - extras, 0, null, null, null); - sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, - null, 0, removedPackage, null, null); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, + removedPackage, extras, 0, null, null, null); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, + removedPackage, extras, 0, null, null, null); + packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, + null, null, 0, removedPackage, null, null); } private void sendPackageRemovedBroadcastInternal(boolean killApp) { @@ -17895,17 +17901,35 @@ public class PackageManagerService extends IPackageManager.Stub { } extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers); if (removedPackage != null) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, 0, null, null, broadcastUsers); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, + removedPackage, extras, 0, null, null, broadcastUsers); if (dataRemoved && !isRemovedPackageSystemUpdate) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, - removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, - null, null, broadcastUsers); + packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, + removedPackage, extras, + Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, + null, null, broadcastUsers); } } if (removedAppId >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, 0, null, null, - broadcastUsers); + packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, + Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, null, broadcastUsers); + } + } + + void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) { + removedUsers = userIds; + if (removedUsers == null) { + broadcastUsers = null; + return; + } + + broadcastUsers = EMPTY_INT_ARRAY; + for (int i = userIds.length - 1; i >= 0; --i) { + final int userId = userIds[i]; + if (deletedPackageSetting.getInstantApp(userId)) { + continue; + } + broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId); } } } @@ -17931,23 +17955,8 @@ public class PackageManagerService extends IPackageManager.Stub { outInfo.removedPackage = packageName; outInfo.isStaticSharedLib = deletedPkg != null && deletedPkg.staticSharedLibName != null; - outInfo.removedUsers = deletedPs != null - ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true) - : null; - if (outInfo.removedUsers == null) { - outInfo.broadcastUsers = null; - } else { - outInfo.broadcastUsers = EMPTY_INT_ARRAY; - int[] allUsers = outInfo.removedUsers; - for (int i = allUsers.length - 1; i >= 0; --i) { - final int userId = allUsers[i]; - if (deletedPs.getInstantApp(userId)) { - continue; - } - outInfo.broadcastUsers = - ArrayUtils.appendInt(outInfo.broadcastUsers, userId); - } - } + outInfo.populateUsers(deletedPs == null ? null + : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs); } } @@ -18430,7 +18439,7 @@ public class PackageManagerService extends IPackageManager.Stub { outInfo.removedChildPackages = new ArrayMap<>(childCount); for (int i = 0; i < childCount; i++) { String childPackageName = ps.childPackageNames.get(i); - PackageRemovedInfo childInfo = new PackageRemovedInfo(); + PackageRemovedInfo childInfo = new PackageRemovedInfo(this); childInfo.removedPackage = childPackageName; outInfo.removedChildPackages.put(childPackageName, childInfo); PackageSetting childPs = mSettings.getPackageLPr(childPackageName); @@ -21692,7 +21701,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName); // Delete package internally - PackageRemovedInfo outInfo = new PackageRemovedInfo(); + PackageRemovedInfo outInfo = new PackageRemovedInfo(this); synchronized (mInstallLock) { final int deleteFlags = PackageManager.DELETE_KEEP_DATA; final boolean res; @@ -21859,7 +21868,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); final ApplicationInfo info = ps.pkg.applicationInfo; final int deleteFlags = PackageManager.DELETE_KEEP_DATA; - final PackageRemovedInfo outInfo = new PackageRemovedInfo(); + final PackageRemovedInfo outInfo = new PackageRemovedInfo(this); try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags, "unloadPrivatePackagesInner")) { @@ -23636,4 +23645,18 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); public ComponentName getInstantAppResolverSettingsComponent() { return mInstantAppResolverSettingsComponent; } + + @Override + public ComponentName getInstantAppInstallerComponent() { + return mInstantAppInstallerActivity == null + ? null : mInstantAppInstallerActivity.getComponentName(); + } +} + +interface PackageSender { + void sendPackageBroadcast(final String action, final String pkg, + final Bundle extras, final int flags, final String targetPkg, + final IIntentReceiver finishedReceiver, final int[] userIds); + void sendPackageAddedForNewUsers(String packageName, boolean isSystem, + int appId, int... userIds); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 4f29bfa2829e..bcb4121a6d2f 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -222,9 +222,10 @@ import android.view.accessibility.AccessibilityManager; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; +import android.view.inputmethod.InputMethodManagerInternal; import android.widget.ImageView; - import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; @@ -279,6 +280,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2; static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3; static final int SHORT_PRESS_POWER_GO_HOME = 4; + static final int SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME = 5; static final int LONG_PRESS_POWER_NOTHING = 0; static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; @@ -407,6 +409,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager mPowerManager; ActivityManagerInternal mActivityManagerInternal; InputManagerInternal mInputManagerInternal; + InputMethodManagerInternal mInputMethodManagerInternal; DreamManagerInternal mDreamManagerInternal; PowerManagerInternal mPowerManagerInternal; IStatusBarService mStatusBarService; @@ -494,6 +497,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mLastInputMethodWindow = null; WindowState mLastInputMethodTargetWindow = null; + @GuardedBy("mLock") + private boolean mDismissImeOnBackKeyPressed; + // FIXME This state is shared between the input reader and handler thread. // Technically it's broken and buggy but it has been like this for many years // and we have not yet seen any problems. Someday we'll rewrite this logic @@ -1396,6 +1402,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { case SHORT_PRESS_POWER_GO_HOME: launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/); break; + case SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME: { + final boolean dismissImeOnBackKeyPressed; + // We can be here on both the main thread (via mHandler) and native callback + // thread (from interceptPowerKeyUp via WindowManagerCallbacks). + synchronized (mLock) { + dismissImeOnBackKeyPressed = mDismissImeOnBackKeyPressed; + } + if (dismissImeOnBackKeyPressed) { + if (mInputMethodManagerInternal == null) { + mInputMethodManagerInternal = + LocalServices.getService(InputMethodManagerInternal.class); + } + if (mInputMethodManagerInternal != null) { + mInputMethodManagerInternal.hideCurrentInputMethod(); + } + } else { + launchHomeFromHotKey(true /* awakenFromDreams */, + false /*respectKeyguard*/); + } + break; + } } } } @@ -7955,6 +7982,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public void setDismissImeOnBackKeyPressed(boolean newValue) { + synchronized (mLock) { + mDismissImeOnBackKeyPressed = newValue; + } + } + + @Override public int getInputMethodWindowVisibleHeightLw() { return mDockBottom - mCurBottom; } @@ -8170,6 +8204,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mLastInputMethodTargetWindow="); pw.println(mLastInputMethodTargetWindow); } + pw.print(prefix); pw.print("mDismissImeOnBackKeyPressed="); + pw.println(mDismissImeOnBackKeyPressed); if (mStatusBar != null) { pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar); pw.print(" isStatusBarKeyguard="); diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 8f114361ccff..f5bb082fac6d 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -406,11 +406,7 @@ final class Notifier { mHandler.post(new Runnable() { @Override public void run() { - LogMaker log = new LogMaker(MetricsEvent.SCREEN); - log.setType(MetricsEvent.TYPE_OPEN); - log.setSubtype(0); // not user initiated - MetricsLogger.action(log); - EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); + // Note a SCREEN tron event is logged in PowerManagerService. mPolicy.startedWakingUp(); } }); @@ -470,7 +466,7 @@ final class Notifier { log.setType(MetricsEvent.TYPE_CLOSE); log.setSubtype(why); MetricsLogger.action(log); - EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0); + EventLogTags.writePowerScreenState(0, why, 0, 0, 0); mPolicy.finishedGoingToSleep(why); } }); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index cf597b052c10..4f239a5cba23 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -32,6 +32,7 @@ import android.hardware.SystemSensorManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.hardware.power.V1_0.PowerHint; +import android.metrics.LogMaker; import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryManagerInternal; @@ -75,6 +76,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; @@ -188,6 +191,11 @@ public final class PowerManagerService extends SystemService // System property indicating that the screen should remain off until an explicit user action private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent"; + private static final String TRACE_SCREEN_ON = "Screen turning on"; + + /** If turning screen on takes more than this long, we show a warning on logcat. */ + private static final int SCREEN_ON_LATENCY_WARNING_MS = 200; + /** Constants for {@link #shutdownOrRebootInternal} */ @Retention(RetentionPolicy.SOURCE) @IntDef({HALT_MODE_SHUTDOWN, HALT_MODE_REBOOT, HALT_MODE_REBOOT_SAFE_MODE}) @@ -1369,6 +1377,8 @@ public final class PowerManagerService extends SystemService return false; } + Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0); + Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp"); try { switch (mWakefulness) { @@ -1551,6 +1561,23 @@ public final class PowerManagerService extends SystemService } } + private void logScreenOn() { + Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0); + + final int latencyMs = (int) (SystemClock.uptimeMillis() - mLastWakeTime); + + LogMaker log = new LogMaker(MetricsEvent.SCREEN); + log.setType(MetricsEvent.TYPE_OPEN); + log.setSubtype(0); // not user initiated + log.setLatency(latencyMs); // How long it took. + MetricsLogger.action(log); + EventLogTags.writePowerScreenState(1, 0, 0, 0, latencyMs); + + if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) { + Slog.w(TAG, "Screen on took " + latencyMs+ " ms"); + } + } + private void finishWakefulnessChangeIfNeededLocked() { if (mWakefulnessChanging && mDisplayReady) { if (mWakefulness == WAKEFULNESS_DOZING @@ -1560,6 +1587,9 @@ public final class PowerManagerService extends SystemService if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) { logSleepTimeoutRecapturedLocked(); } + if (mWakefulness == WAKEFULNESS_AWAKE) { + logScreenOn(); + } mWakefulnessChanging = false; mNotifier.onWakefulnessChangeFinished(); } diff --git a/services/core/java/com/android/server/storage/AppCollector.java b/services/core/java/com/android/server/storage/AppCollector.java index a77d33f8514b..03b754f777b3 100644 --- a/services/core/java/com/android/server/storage/AppCollector.java +++ b/services/core/java/com/android/server/storage/AppCollector.java @@ -21,22 +21,21 @@ import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageStats; import android.content.pm.UserInfo; import android.os.Handler; -import android.os.HandlerThread; import android.os.Looper; import android.os.Message; -import android.os.Process; -import android.os.RemoteException; import android.os.UserManager; import android.os.storage.VolumeInfo; import android.util.Log; + import com.android.internal.os.BackgroundThread; import com.android.internal.util.Preconditions; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -44,7 +43,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; /** * AppCollector asynchronously collects package sizes. @@ -132,7 +130,7 @@ public class AppCollector { try { StorageStats storageStats = - mStorageStatsManager.queryStatsForPackage(app.volumeUuid, + mStorageStatsManager.queryStatsForPackage(app.storageUuid, app.packageName, user.getUserHandle()); PackageStats packageStats = new PackageStats(app.packageName, user.id); @@ -140,7 +138,7 @@ public class AppCollector { packageStats.codeSize = storageStats.getCodeBytes(); packageStats.dataSize = storageStats.getDataBytes(); stats.add(packageStats); - } catch (IllegalStateException e) { + } catch (NameNotFoundException | IOException e) { Log.e(TAG, "An exception occurred while fetching app size", e); } } diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index f41eed53cbca..e6345523bd14 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -22,6 +22,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.animation.Animator; import android.animation.ValueAnimator; +import android.annotation.IntDef; import android.content.Context; import android.graphics.Rect; import android.os.Handler; @@ -35,6 +36,9 @@ import android.view.WindowManagerInternal; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Enables animating bounds of objects. * @@ -43,7 +47,7 @@ import com.android.internal.annotations.VisibleForTesting; * relaunching it would cause poorer experience), these class provides a way to directly animate * the bounds of the resized object. * - * The object that is resized needs to implement {@link AnimateBoundsUser} interface. + * The object that is resized needs to implement {@link BoundsAnimationTarget} interface. * * NOTE: All calls to methods in this class should be done on the UI thread */ @@ -56,8 +60,19 @@ public class BoundsAnimationController { private static final int DEFAULT_TRANSITION_DURATION = 425; + @Retention(RetentionPolicy.SOURCE) + @IntDef({NO_PIP_MODE_CHANGED_CALLBACKS, SCHEDULE_PIP_MODE_CHANGED_ON_START, + SCHEDULE_PIP_MODE_CHANGED_ON_END}) + public @interface SchedulePipModeChangedState {} + /** Do not schedule any PiP mode changed callbacks as a part of this animation. */ + public static final int NO_PIP_MODE_CHANGED_CALLBACKS = 0; + /** Schedule a PiP mode changed callback when this animation starts. */ + public static final int SCHEDULE_PIP_MODE_CHANGED_ON_START = 1; + /** Schedule a PiP mode changed callback when this animation ends. */ + public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2; + // Only accessed on UI thread. - private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); + private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); private final class AppTransitionNotifier extends WindowManagerInternal.AppTransitionListener implements Runnable { @@ -108,40 +123,42 @@ public class BoundsAnimationController { @VisibleForTesting final class BoundsAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { - private final AnimateBoundsUser mTarget; + private final BoundsAnimationTarget mTarget; private final Rect mFrom = new Rect(); private final Rect mTo = new Rect(); private final Rect mTmpRect = new Rect(); private final Rect mTmpTaskBounds = new Rect(); - private final boolean mMoveToFullScreen; - // True if this this animation was cancelled and will be replaced the another animation from - // the same {@link #AnimateBoundsUser} target. + + // True if this this animation was canceled and will be replaced the another animation from + // the same {@link #BoundsAnimationTarget} target. private boolean mSkipFinalResize; // True if this animation replaced a previous animation of the same - // {@link #AnimateBoundsUser} target. + // {@link #BoundsAnimationTarget} target. private final boolean mSkipAnimationStart; - // True if this animation was cancelled by the user, not as a part of a replacing animation + // True if this animation was canceled by the user, not as a part of a replacing animation private boolean mSkipAnimationEnd; - // True if this animation is not replacing a previous animation, or if the previous - // animation is animating to a different fullscreen state than the current animation. - // We use this to ensure that we always provide a consistent set/order of callbacks when we - // transition to/from PiP. - private final boolean mAnimatingToNewFullscreenState; + // True if the animation target should be moved to the fullscreen stack at the end of this + // animation + private boolean mMoveToFullscreen; + + // Whether to schedule PiP mode changes on animation start/end + private @SchedulePipModeChangedState int mSchedulePipModeChangedState; // Depending on whether we are animating from // a smaller to a larger size private final int mFrozenTaskWidth; private final int mFrozenTaskHeight; - BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to, boolean moveToFullScreen, - boolean replacingExistingAnimation, boolean animatingToNewFullscreenState) { + BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to, + @SchedulePipModeChangedState int schedulePipModeChangedState, + boolean moveToFullscreen, boolean replacingExistingAnimation) { super(); mTarget = target; mFrom.set(from); mTo.set(to); - mMoveToFullScreen = moveToFullScreen; mSkipAnimationStart = replacingExistingAnimation; - mAnimatingToNewFullscreenState = animatingToNewFullscreenState; + mSchedulePipModeChangedState = schedulePipModeChangedState; + mMoveToFullscreen = moveToFullscreen; addUpdateListener(this); addListener(this); @@ -161,7 +178,8 @@ public class BoundsAnimationController { @Override public void onAnimationStart(Animator animation) { if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget - + " mSkipAnimationStart=" + mSkipAnimationStart); + + " mSkipAnimationStart=" + mSkipAnimationStart + + " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState); mFinishAnimationAfterTransition = false; mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth, mFrom.top + mFrozenTaskHeight); @@ -170,13 +188,8 @@ public class BoundsAnimationController { // we trigger any size changes, so it can swap surfaces // in to appropriate modes, or do as it wishes otherwise. if (!mSkipAnimationStart) { - mTarget.onAnimationStart(mMoveToFullScreen); - } - - // If we are animating to a new fullscreen state (either to/from fullscreen), then - // notify the target of the change with the new frozen task bounds - if (mAnimatingToNewFullscreenState && mMoveToFullScreen) { - mTarget.updatePictureInPictureMode(null); + mTarget.onAnimationStart(mSchedulePipModeChangedState == + SCHEDULE_PIP_MODE_CHANGED_ON_START); } // Immediately update the task bounds if they have to become larger, but preserve @@ -206,20 +219,26 @@ public class BoundsAnimationController { // any further animation. if (DEBUG) Slog.d(TAG, "animateUpdate: cancelled"); + // If we have already scheduled a PiP mode changed at the start of the animation, + // then we need to clean up and schedule one at the end, since we have canceled the + // animation to the final state. + if (mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + mSchedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; + } + // Since we are cancelling immediately without a replacement animation, send the // animation end to maintain callback parity, but also skip any further resizes - prepareCancel(false /* skipAnimationEnd */, true /* skipFinalResize */); - cancel(); + cancelAndCallAnimationEnd(); } } @Override public void onAnimationEnd(Animator animation) { if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget - + " mMoveToFullScreen=" + mMoveToFullScreen + " mSkipFinalResize=" + mSkipFinalResize + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition - + " mAppTransitionIsRunning=" + mAppTransition.isRunning()); + + " mAppTransitionIsRunning=" + mAppTransition.isRunning() + + " callers=" + Debug.getCallers(2)); // There could be another animation running. For example in the // move to fullscreen case, recents will also be closing while the @@ -231,58 +250,57 @@ public class BoundsAnimationController { return; } - if (!mSkipFinalResize) { - // If not cancelled, resize the pinned stack to the final size. All calls to - // setPinnedStackSize() must be done between onAnimationStart() and onAnimationEnd() - mTarget.setPinnedStackSize(mTo, null); + if (!mSkipAnimationEnd) { + // If this animation has already scheduled the picture-in-picture mode on start, and + // we are not skipping the final resize due to being canceled, then move the PiP to + // fullscreen once the animation ends + if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget + + " moveToFullscreen=" + mMoveToFullscreen); + mTarget.onAnimationEnd(mSchedulePipModeChangedState == + SCHEDULE_PIP_MODE_CHANGED_ON_END, !mSkipFinalResize ? mTo : null, + mMoveToFullscreen); } - finishAnimation(); - - if (mMoveToFullScreen && !mSkipFinalResize) { - mTarget.moveToFullscreen(); - } + // Clean up this animation + removeListener(this); + removeUpdateListener(this); + mRunningAnimations.remove(mTarget); } @Override public void onAnimationCancel(Animator animation) { - finishAnimation(); + // Always skip the final resize when the animation is canceled + mSkipFinalResize = true; + mMoveToFullscreen = false; } - public void prepareCancel(boolean skipAnimationEnd, boolean skipFinalResize) { - if (DEBUG) Slog.d(TAG, "prepareCancel: skipAnimationEnd=" + skipAnimationEnd - + " skipFinalResize=" + skipFinalResize); - mSkipAnimationEnd = skipAnimationEnd; - mSkipFinalResize = skipFinalResize; + private void cancelAndCallAnimationEnd() { + if (DEBUG) Slog.d(TAG, "cancelAndCallAnimationEnd: mTarget=" + mTarget); + mSkipAnimationEnd = false; + super.cancel(); } @Override public void cancel() { if (DEBUG) Slog.d(TAG, "cancel: mTarget=" + mTarget); + mSkipAnimationEnd = true; super.cancel(); } - /** Returns true if the animation target is the same as the input bounds. */ + /** + * @return true if the animation target is the same as the input bounds. + */ boolean isAnimatingTo(Rect bounds) { return mTo.equals(bounds); } - private boolean animatingToLargerSize() { - if (mFrom.width() * mFrom.height() > mTo.width() * mTo.height()) { - return false; - } - return true; - } - - private void finishAnimation() { - if (DEBUG) Slog.d(TAG, "finishAnimation: mTarget=" + mTarget - + " callers" + Debug.getCallers(2)); - if (!mSkipAnimationEnd) { - mTarget.onAnimationEnd(); - } - removeListener(this); - removeUpdateListener(this); - mRunningAnimations.remove(mTarget); + /** + * @return true if we are animating to a larger surface size + */ + @VisibleForTesting + boolean animatingToLargerSize() { + // TODO: Fix this check for aspect ratio changes + return (mFrom.width() * mFrom.height() <= mTo.width() * mTo.height()); } @Override @@ -291,63 +309,23 @@ public class BoundsAnimationController { } } - public interface AnimateBoundsUser { - /** - * Sets the size of the target (without any intermediate steps, like scheduling animation) - * but freezes the bounds of any tasks in the target at taskBounds, - * to allow for more flexibility during resizing. Only works for the pinned stack at the - * moment. - * - * @return Whether the target should continue to be animated and this call was successful. - * If false, the animation will be cancelled because the user has determined that the - * animation is now invalid and not required. In such a case, the cancel will trigger the - * animation end callback as well, but will not send any further size changes. - */ - boolean setPinnedStackSize(Rect bounds, Rect taskBounds); - - /** - * Callback for the target to inform it that the animation has started, so it can do some - * necessary preparation. - */ - void onAnimationStart(boolean toFullscreen); - - /** - * Callback for the target to inform it that the animation is going to a new fullscreen - * state and should update the picture-in-picture mode accordingly. - * - * @param targetStackBounds the target stack bounds we are animating to, can be null if - * we are animating to fullscreen - */ - void updatePictureInPictureMode(Rect targetStackBounds); - - /** - * Callback for the target to inform it that the animation has ended, so it can do some - * necessary cleanup. - */ - void onAnimationEnd(); - - /** - * Callback for the target to inform it to reparent to the fullscreen stack. - */ - void moveToFullscreen(); - } - - public void animateBounds(final AnimateBoundsUser target, Rect from, Rect to, - int animationDuration, boolean moveToFullscreen) { - animateBoundsImpl(target, from, to, animationDuration, moveToFullscreen); + public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to, + int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, + boolean moveToFullscreen) { + animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState, + moveToFullscreen); } @VisibleForTesting - BoundsAnimator animateBoundsImpl(final AnimateBoundsUser target, Rect from, Rect to, - int animationDuration, boolean moveToFullscreen) { + BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to, + int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, + boolean moveToFullscreen) { final BoundsAnimator existing = mRunningAnimations.get(target); final boolean replacing = existing != null; - final boolean animatingToNewFullscreenState = (existing == null) || - (existing.mMoveToFullScreen != moveToFullscreen); if (DEBUG) Slog.d(TAG, "animateBounds: target=" + target + " from=" + from + " to=" + to - + " moveToFullscreen=" + moveToFullscreen + " replacing=" + replacing - + " animatingToNewFullscreenState=" + animatingToNewFullscreenState); + + " schedulePipModeChangedState=" + schedulePipModeChangedState + + " replacing=" + replacing); if (replacing) { if (existing.isAnimatingTo(to)) { @@ -355,15 +333,36 @@ public class BoundsAnimationController { // one we are trying to start. if (DEBUG) Slog.d(TAG, "animateBounds: same destination as existing=" + existing + " ignoring..."); + return existing; } - // Since we are replacing, we skip both animation start and end callbacks, and don't - // animate to the final bounds when cancelling - existing.prepareCancel(true /* skipAnimationEnd */, true /* skipFinalResize */); + + // Update the PiP callback states if we are replacing the animation + if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + if (DEBUG) Slog.d(TAG, "animateBounds: still animating to fullscreen, keep" + + " existing deferred state"); + } else { + if (DEBUG) Slog.d(TAG, "animateBounds: fullscreen animation canceled, callback" + + " on start already processed, schedule deferred update on end"); + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; + } + } else if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END) { + if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) { + if (DEBUG) Slog.d(TAG, "animateBounds: non-fullscreen animation canceled," + + " callback on start will be processed"); + } else { + if (DEBUG) Slog.d(TAG, "animateBounds: still animating from fullscreen, keep" + + " existing deferred state"); + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; + } + } + + // Since we are replacing, we skip both animation start and end callbacks existing.cancel(); } - final BoundsAnimator animator = new BoundsAnimator(target, from, to, moveToFullscreen, - replacing, animatingToNewFullscreenState); + final BoundsAnimator animator = new BoundsAnimator(target, from, to, + schedulePipModeChangedState, moveToFullscreen, replacing); mRunningAnimations.put(target, animator); animator.setFloatValues(0f, 1f); animator.setDuration((animationDuration != -1 ? animationDuration diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java new file mode 100644 index 000000000000..8b1bf7bf77dc --- /dev/null +++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java @@ -0,0 +1,62 @@ +/* + * 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.server.wm; + +import android.graphics.Rect; + +/** + * The target for a BoundsAnimation. + * @see BoundsAnimationController + */ +interface BoundsAnimationTarget { + + /** + * Callback for the target to inform it that the animation has started, so it can do some + * necessary preparation. + * + * @param schedulePipModeChangedCallback whether or not to schedule the PiP mode changed + * callbacks + */ + void onAnimationStart(boolean schedulePipModeChangedCallback); + + /** + * Sets the size of the target (without any intermediate steps, like scheduling animation) + * but freezes the bounds of any tasks in the target at taskBounds, to allow for more + * flexibility during resizing. Only works for the pinned stack at the moment. This will + * only be called between onAnimationStart() and onAnimationEnd(). + * + * @return Whether the target should continue to be animated and this call was successful. + * If false, the animation will be cancelled because the user has determined that the + * animation is now invalid and not required. In such a case, the cancel will trigger the + * animation end callback as well, but will not send any further size changes. + */ + boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds); + + /** + * Callback for the target to inform it that the animation has ended, so it can do some + * necessary cleanup. + * + * @param schedulePipModeChangedCallback whether or not to schedule the PiP mode changed + * callbacks + * @param finalStackSize the final stack bounds to set on the target (can be to indicate that + * the animation was cancelled and the target does not need to update to the final stack bounds) + * @param moveToFullscreen whether or the target should reparent itself to the fullscreen stack + * when the animation completes + */ + void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize, + boolean moveToFullscreen); +} diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 058fdae17f9f..182361015a05 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -125,6 +125,7 @@ import android.view.Surface; import android.view.SurfaceControl; import android.view.WindowManagerPolicy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; import com.android.internal.view.IInputMethodClient; @@ -1396,6 +1397,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return null; } + @VisibleForTesting + int getStackCount() { + return mTaskStackContainers.size(); + } + + @VisibleForTesting + int getStaskPosById(int stackId) { + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); + if (stack.mStackId == stackId) { + return i; + } + } + return -1; + } + @Override void onConfigurationChanged(Configuration newParentConfig) { super.onConfigurationChanged(newParentConfig); @@ -3274,8 +3291,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo : requestedPosition >= topChildPosition; int targetPosition = requestedPosition; - if (toTop && isStackVisible(PINNED_STACK_ID) && stack.mStackId != PINNED_STACK_ID) { - // The pinned stack is always the top most stack (always-on-top) when it is visible. + if (toTop && stack.mStackId != PINNED_STACK_ID + && getStackById(PINNED_STACK_ID) != null) { + // The pinned stack is always the top most stack (always-on-top) when it is present. TaskStack topStack = mChildren.get(topChildPosition); if (topStack.mStackId != PINNED_STACK_ID) { throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren); diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index 16848780fe47..82416ec513c4 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -26,7 +26,6 @@ import android.app.RemoteAction; import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -123,6 +122,13 @@ class PinnedStackController { mSnapAlgorithm.setMinimized(isMinimized); }); } + + @Override + public int getDisplayRotation() { + synchronized (mService.mWindowMap) { + return mDisplayInfo.rotation; + } + } } /** @@ -221,22 +227,26 @@ class PinnedStackController { * @return the size of the PIP based on the given {@param aspectRatio}. */ Size getSize(float aspectRatio) { - return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize, - mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + synchronized (mService.mWindowMap) { + return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize, + mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + } } /** * @return the default bounds to show the PIP when there is no active PIP. */ Rect getDefaultBounds() { - final Rect insetBounds = new Rect(); - getInsetBounds(insetBounds); - - final Rect defaultBounds = new Rect(); - final Size size = getSize(mDefaultAspectRatio); - Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds, - 0, mIsImeShowing ? mImeHeight : 0, defaultBounds); - return defaultBounds; + synchronized (mService.mWindowMap) { + final Rect insetBounds = new Rect(); + getInsetBounds(insetBounds); + + final Rect defaultBounds = new Rect(); + final Size size = getSize(mDefaultAspectRatio); + Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds, + 0, mIsImeShowing ? mImeHeight : 0, defaultBounds); + return defaultBounds; + } } /** @@ -254,42 +264,44 @@ class PinnedStackController { * new orientation of the device if necessary. */ boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) { - final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); - if (mDisplayInfo.equals(displayInfo)) { - // We are already in the right orientation, ignore - outBounds.setEmpty(); - return false; - } else if (targetBounds.isEmpty()) { - // The stack is null, we are just initializing the stack, so just store the display info - // and ignore + synchronized (mService.mWindowMap) { + final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); + if (mDisplayInfo.equals(displayInfo)) { + // We are already in the right orientation, ignore + outBounds.setEmpty(); + return false; + } else if (targetBounds.isEmpty()) { + // The stack is null, we are just initializing the stack, so just store the display + // info and ignore + mDisplayInfo.copyFrom(displayInfo); + outBounds.setEmpty(); + return false; + } + + mTmpRect.set(targetBounds); + final Rect postChangeStackBounds = mTmpRect; + + // Calculate the snap fraction of the current stack along the old movement bounds + final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds); + final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds, + preChangeMovementBounds); mDisplayInfo.copyFrom(displayInfo); - outBounds.setEmpty(); - return false; - } - mTmpRect.set(targetBounds); - final Rect postChangeStackBounds = mTmpRect; - - // Calculate the snap fraction of the current stack along the old movement bounds - final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds); - final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds, - preChangeMovementBounds); - mDisplayInfo.copyFrom(displayInfo); - - // Calculate the stack bounds in the new orientation to the same same fraction along the - // rotated movement bounds. - final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds, - false /* adjustForIme */); - mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, - snapFraction); - if (mIsMinimized) { - applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds); - } + // Calculate the stack bounds in the new orientation to the same same fraction along the + // rotated movement bounds. + final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds, + false /* adjustForIme */); + mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, + snapFraction); + if (mIsMinimized) { + applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds); + } - notifyMovementBoundsChanged(false /* fromImeAdjustment */); + notifyMovementBoundsChanged(false /* fromImeAdjustment */); - outBounds.set(postChangeStackBounds); - return true; + outBounds.set(postChangeStackBounds); + return true; + } } /** @@ -378,25 +390,27 @@ class PinnedStackController { * Notifies listeners that the PIP movement bounds have changed. */ private void notifyMovementBoundsChanged(boolean fromImeAdjustement) { - if (mPinnedStackListener != null) { - try { - final Rect insetBounds = new Rect(); - getInsetBounds(insetBounds); - final Rect normalBounds = getDefaultBounds(); - if (isValidPictureInPictureAspectRatio(mAspectRatio)) { - transformBoundsToAspectRatio(normalBounds, mAspectRatio); - } - final Rect animatingBounds = mTmpAnimatingBoundsRect; - final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID); - if (pinnedStack != null) { - pinnedStack.getAnimationOrCurrentBounds(animatingBounds); - } else { - animatingBounds.set(normalBounds); + synchronized (mService.mWindowMap) { + if (mPinnedStackListener != null) { + try { + final Rect insetBounds = new Rect(); + getInsetBounds(insetBounds); + final Rect normalBounds = getDefaultBounds(); + if (isValidPictureInPictureAspectRatio(mAspectRatio)) { + transformBoundsToAspectRatio(normalBounds, mAspectRatio); + } + final Rect animatingBounds = mTmpAnimatingBoundsRect; + final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID); + if (pinnedStack != null) { + pinnedStack.getAnimationOrCurrentBounds(animatingBounds); + } else { + animatingBounds.set(normalBounds); + } + mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds, + animatingBounds, fromImeAdjustement, mDisplayInfo.rotation); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering actions changed event.", e); } - mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds, - animatingBounds, fromImeAdjustement); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering actions changed event.", e); } } } @@ -405,11 +419,13 @@ class PinnedStackController { * @return the bounds on the screen that the PIP can be visible in. */ private void getInsetBounds(Rect outRect) { - mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth, - mDisplayInfo.logicalHeight, mTmpInsets); - outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y, - mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x, - mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y); + synchronized (mService.mWindowMap) { + mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth, + mDisplayInfo.logicalHeight, mTmpInsets); + outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y, + mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x, + mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y); + } } /** @@ -417,7 +433,9 @@ class PinnedStackController { * controller. */ private Rect getMovementBounds(Rect stackBounds) { - return getMovementBounds(stackBounds, true /* adjustForIme */); + synchronized (mService.mWindowMap) { + return getMovementBounds(stackBounds, true /* adjustForIme */); + } } /** @@ -425,23 +443,27 @@ class PinnedStackController { * controller. */ private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) { - final Rect movementBounds = new Rect(); - getInsetBounds(movementBounds); - - // Apply the movement bounds adjustments based on the current state - mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds, - (adjustForIme && mIsImeShowing) ? mImeHeight : 0); - return movementBounds; + synchronized (mService.mWindowMap) { + final Rect movementBounds = new Rect(); + getInsetBounds(movementBounds); + + // Apply the movement bounds adjustments based on the current state + mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds, + (adjustForIme && mIsImeShowing) ? mImeHeight : 0); + return movementBounds; + } } /** * Applies the minimized offsets to the given stack bounds. */ private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) { - mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); - mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets); - mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize, - mStableInsets); + synchronized (mService.mWindowMap) { + mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets); + mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize, + mStableInsets); + } } /** diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java index 135832e619a4..5b9c16ce60c9 100644 --- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java +++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java @@ -17,6 +17,10 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START; +import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState; import android.app.RemoteAction; import android.graphics.Rect; @@ -40,36 +44,53 @@ public class PinnedStackWindowController extends StackWindowController { /** * Animates the pinned stack. */ - public void animateResizePinnedStack(Rect sourceBounds, Rect destBounds, - int animationDuration) { + public void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds, + int animationDuration, boolean schedulePipModeChangedOnAnimationEnd) { synchronized (mWindowMap) { if (mContainer == null) { throw new IllegalArgumentException("Pinned stack container not found :("); } - // Get non-null fullscreen bounds if the bounds are null - final boolean moveToFullscreen = destBounds == null; - destBounds = getPinnedStackAnimationBounds(destBounds); - - // If the bounds are truly null, then there was no fullscreen stack at this time, so - // animate this to the full display bounds - final Rect toBounds; - if (destBounds == null) { - toBounds = new Rect(); - mContainer.getDisplayContent().getLogicalDisplayRect(toBounds); - } else { - toBounds = destBounds; + // Get the from-bounds + final Rect fromBounds = new Rect(); + mContainer.getBounds(fromBounds); + + // Get non-null fullscreen to-bounds for animating if the bounds are null + @SchedulePipModeChangedState int schedulePipModeChangedState = + NO_PIP_MODE_CHANGED_CALLBACKS; + final boolean toFullscreen = toBounds == null; + if (toFullscreen) { + if (schedulePipModeChangedOnAnimationEnd) { + throw new IllegalArgumentException("Should not defer scheduling PiP mode" + + " change on animation to fullscreen."); + } + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START; + + mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpBoundsRect); + if (!mTmpBoundsRect.isEmpty()) { + // If there is a fullscreen bounds, use that + toBounds = new Rect(mTmpBoundsRect); + } else { + // Otherwise, use the display bounds + toBounds = new Rect(); + mContainer.getDisplayContent().getLogicalDisplayRect(toBounds); + } + } else if (schedulePipModeChangedOnAnimationEnd) { + schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; } - final Rect originalBounds = new Rect(); - mContainer.getBounds(originalBounds); - mContainer.setAnimationFinalBounds(sourceBounds, toBounds); + mContainer.setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen); + + final Rect finalToBounds = toBounds; + final @SchedulePipModeChangedState int finalSchedulePipModeChangedState = + schedulePipModeChangedState; UiThread.getHandler().post(() -> { if (mContainer == null) { return; } - mService.mBoundsAnimationController.animateBounds(mContainer, originalBounds, - toBounds, animationDuration, moveToFullscreen); + mService.mBoundsAnimationController.animateBounds(mContainer, fromBounds, + finalToBounds, animationDuration, finalSchedulePipModeChangedState, + toFullscreen); }); } } @@ -93,7 +114,8 @@ public class PinnedStackWindowController extends StackWindowController { if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) { if (!toBounds.equals(targetBounds)) { - animateResizePinnedStack(null /* sourceBounds */, toBounds, -1 /* duration */); + animateResizePinnedStack(toBounds, null /* sourceHintBounds */, + -1 /* duration */, false /* schedulePipModeChangedOnAnimationEnd */); } pinnedStackController.setAspectRatio( pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio) @@ -116,26 +138,31 @@ public class PinnedStackWindowController extends StackWindowController { } /** - * @return whether the bounds are currently animating to fullscreen. + * @return whether the multi-window mode change should be deferred as a part of a transition + * from fullscreen to non-fullscreen bounds. */ - public boolean isAnimatingBoundsToFullscreen() { - return mContainer.isAnimatingBoundsToFullscreen(); + public boolean deferScheduleMultiWindowModeChanged() { + synchronized(mWindowMap) { + return mContainer.deferScheduleMultiWindowModeChanged(); + } } - public boolean pinnedStackResizeAllowed() { - return mContainer.pinnedStackResizeAllowed(); + /** + * @return whether the bounds are currently animating to fullscreen. + */ + public boolean isAnimatingBoundsToFullscreen() { + synchronized (mWindowMap) { + return mContainer.isAnimatingBoundsToFullscreen(); + } } /** - * Checks the {@param bounds} and retirms non-null fullscreen bounds for the pinned stack - * animation if necessary. + * @return whether the stack can be resized from the bounds animation. */ - private Rect getPinnedStackAnimationBounds(Rect bounds) { - mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpBoundsRect); - if (bounds == null && !mTmpBoundsRect.isEmpty()) { - bounds = new Rect(mTmpBoundsRect); + public boolean pinnedStackResizeDisallowed() { + synchronized (mWindowMap) { + return mContainer.pinnedStackResizeDisallowed(); } - return bounds; } /** diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index d7c41d335b72..d141f7cb2eb3 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -56,7 +56,7 @@ import com.android.server.EventLogTags; import java.io.PrintWriter; public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLayerUser, - BoundsAnimationController.AnimateBoundsUser { + BoundsAnimationTarget { /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to * restrict IME adjustment so that a min portion of top stack remains visible.*/ private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f; @@ -132,7 +132,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye private boolean mBoundsAnimatingToFullscreen = false; private boolean mCancelCurrentBoundsAnimation = false; private Rect mBoundsAnimationTarget = new Rect(); - private Rect mBoundsAnimationSourceBounds = new Rect(); + private Rect mBoundsAnimationSourceHintBounds = new Rect(); // Temporary storage for the new bounds that should be used after the configuration change. // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). @@ -322,18 +322,19 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye * Sets the bounds animation target bounds ahead of an animation. This can't currently be done * in onAnimationStart() since that is started on the UiThread. */ - void setAnimationFinalBounds(Rect sourceBounds, Rect destBounds) { + void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds, boolean toFullscreen) { mBoundsAnimatingRequested = true; - if (sourceBounds != null) { - mBoundsAnimationSourceBounds.set(sourceBounds); - } else { - mBoundsAnimationSourceBounds.setEmpty(); - } + mBoundsAnimatingToFullscreen = toFullscreen; if (destBounds != null) { mBoundsAnimationTarget.set(destBounds); } else { mBoundsAnimationTarget.setEmpty(); } + if (sourceHintBounds != null) { + mBoundsAnimationSourceHintBounds.set(sourceHintBounds); + } else { + mBoundsAnimationSourceHintBounds.setEmpty(); + } } /** @@ -346,8 +347,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye /** * @return the final source bounds for the bounds animation. */ - void getFinalAnimationSourceBounds(Rect outBounds) { - outBounds.set(mBoundsAnimationSourceBounds); + void getFinalAnimationSourceHintBounds(Rect outBounds) { + outBounds.set(mBoundsAnimationSourceHintBounds); } /** @@ -413,7 +414,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye // orientation, clear the animation target bounds since they are obsolete, and // cancel any currently running animations mBoundsAnimationTarget.setEmpty(); - mBoundsAnimationSourceBounds.setEmpty(); + mBoundsAnimationSourceHintBounds.setEmpty(); mCancelCurrentBoundsAnimation = true; return true; } @@ -1458,13 +1459,16 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } } - public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) { - if (mCancelCurrentBoundsAnimation) { - return false; + public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) { + // Hold the lock since this is called from the BoundsAnimator running on the UiThread + synchronized (mService.mWindowMap) { + if (mCancelCurrentBoundsAnimation) { + return false; + } } try { - mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds); + mService.mActivityManager.resizePinnedStack(stackBounds, tempTaskBounds); } catch (RemoteException e) { // I don't believe you. } @@ -1472,11 +1476,11 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } @Override // AnimatesBounds - public void onAnimationStart(boolean toFullscreen) { + public void onAnimationStart(boolean schedulePipModeChangedCallback) { + // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mService.mWindowMap) { mBoundsAnimatingRequested = false; mBoundsAnimating = true; - mBoundsAnimatingToFullscreen = toFullscreen; mCancelCurrentBoundsAnimation = false; } @@ -1486,41 +1490,63 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } catch (RemoteException e) { // I don't believe you... } - } - } - @Override // AnimatesBounds - public void updatePictureInPictureMode(Rect targetStackBounds) { - final PinnedStackWindowController controller = - (PinnedStackWindowController) getController(); - if (controller != null) { - controller.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds); + final PinnedStackWindowController controller = + (PinnedStackWindowController) getController(); + if (schedulePipModeChangedCallback && controller != null) { + // We need to schedule the PiP mode change after the animation down, so use the + // final bounds + controller.updatePictureInPictureModeForPinnedStackAnimation(null); + } } } @Override // AnimatesBounds - public void onAnimationEnd() { + public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize, + boolean moveToFullscreen) { + // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mService.mWindowMap) { mBoundsAnimating = false; mService.requestTraversal(); } if (mStackId == PINNED_STACK_ID) { + final PinnedStackWindowController controller = + (PinnedStackWindowController) getController(); + if (schedulePipModeChangedCallback && controller != null) { + // We need to schedule the PiP mode change after the animation down, so use the + // final bounds + controller.updatePictureInPictureModeForPinnedStackAnimation( + mBoundsAnimationTarget); + } + + // Update to the final bounds if requested. This is done here instead of in the bounds + // animator to allow us to coordinate this after we notify the PiP mode changed + if (finalStackSize != null) { + setPinnedStackSize(finalStackSize, null); + } + try { mService.mActivityManager.notifyPinnedStackAnimationEnded(); + if (moveToFullscreen) { + mService.mActivityManager.moveTasksToFullscreenStack(mStackId, + true /* onTop */); + } } catch (RemoteException e) { // I don't believe you... } } } - @Override - public void moveToFullscreen() { - try { - mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true); - } catch (RemoteException e) { - e.printStackTrace(); + /** + * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen + * bounds and we have a deferred PiP mode changed callback set with the animation. + */ + public boolean deferScheduleMultiWindowModeChanged() { + if (mStackId == PINNED_STACK_ID) { + return (mBoundsAnimatingRequested || mBoundsAnimating); } + return false; } public boolean hasMovementAnimations() { @@ -1539,7 +1565,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye return mBoundsAnimating && mBoundsAnimatingToFullscreen; } - public boolean pinnedStackResizeAllowed() { + public boolean pinnedStackResizeDisallowed() { if (mBoundsAnimating && mCancelCurrentBoundsAnimation) { return true; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0049585f5c52..252b4d4e0473 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7267,13 +7267,16 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void updateInputMethodWindowStatus(@NonNull IBinder imeToken, - boolean imeWindowVisible, @Nullable IBinder targetWindowToken) { + boolean imeWindowVisible, boolean dismissImeOnBackKeyPressed, + @Nullable IBinder targetWindowToken) { // TODO (b/34628091): Use this method to address the window animation issue. if (DEBUG_INPUT_METHOD) { Slog.w(TAG_WM, "updateInputMethodWindowStatus: imeToken=" + imeToken + + " dismissImeOnBackKeyPressed=" + dismissImeOnBackKeyPressed + " imeWindowVisible=" + imeWindowVisible + " targetWindowToken=" + targetWindowToken); } + mPolicy.setDismissImeOnBackKeyPressed(dismissImeOnBackKeyPressed); } @Override diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 0b96f3fbc1fc..9555c8dff03c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4365,9 +4365,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // When we change the Surface size, in scenarios which may require changing // the surface position in sync with the resize, we use a preserved surface // so we can freeze it while waiting for the client to report draw on the newly - // sized surface. + // sized surface. Don't preserve surfaces if the insets change while animating the pinned + // stack since it can lead to issues if a new surface is created while calculating the + // scale for the animation using the source hint rect + // (see WindowStateAnimator#setSurfaceBoundariesLocked()). if (isDragResizeChanged() || isResizedWhileNotDragResizing() - || surfaceInsetsChanging()) { + || (surfaceInsetsChanging() && !inPinnedWorkspace())) { mLastSurfaceInsets.set(mAttrs.surfaceInsets); setDragResizing(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index fa353367c6e4..a2889b145f16 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1360,7 +1360,7 @@ class WindowStateAnimator { int posX = mTmpSize.left; int posY = mTmpSize.top; task.mStack.getDimBounds(mTmpStackBounds); - task.mStack.getFinalAnimationSourceBounds(mTmpSourceBounds); + task.mStack.getFinalAnimationSourceHintBounds(mTmpSourceBounds); if (!mTmpSourceBounds.isEmpty()) { // Get the final target stack bounds, if we are not animating, this is just the // current stack bounds diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp index d834e2527e08..20466ebb0ef5 100644 --- a/services/core/jni/com_android_server_location_ContextHubService.cpp +++ b/services/core/jni/com_android_server_location_ContextHubService.cpp @@ -1129,6 +1129,8 @@ jint nativeSendMessage(JNIEnv *env, if (appInstanceHandle == OS_APP_ID) { if (msgType == CONTEXT_HUB_LOAD_APP) { result = sendLoadNanoAppRequest(hubId, data, dataBufferLength); + } else if (msgType == CONTEXT_HUB_QUERY_APPS) { + result = db.hubInfo.contextHub->queryApps(hubId); } else { ALOGD("Dropping OS addresses message of type - %" PRIu32, msgType); result = Result::BAD_PARAMS; diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 86662b94302e..74ecd11d13f4 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -68,12 +68,15 @@ static JavaVM* sJvm; using android::OK; using android::sp; +using android::wp; using android::status_t; using android::String16; using android::hardware::Return; using android::hardware::Void; using android::hardware::hidl_vec; +using android::hardware::hidl_death_recipient; +using android::hidl::base::V1_0::IBase; using android::hardware::gnss::V1_0::IAGnss; using android::hardware::gnss::V1_0::IAGnssCallback; @@ -97,7 +100,18 @@ using android::hardware::gnss::V1_0::IGnssNiCallback; using android::hardware::gnss::V1_0::IGnssXtra; using android::hardware::gnss::V1_0::IGnssXtraCallback; +struct GnssDeathRecipient : virtual public hidl_death_recipient +{ + // hidl_death_recipient interface + virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override { + // TODO(gomo): implement a better death recovery mechanism without + // crashing system server process as described in go//treble-gnss-death + LOG_ALWAYS_FATAL("Abort due to IGNSS hidl service failure," + " restarting system server"); + } +}; +sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr; sp<IGnss> gnssHal = nullptr; sp<IGnssXtra> gnssXtraIface = nullptr; sp<IAGnssRil> agnssRilIface = nullptr; @@ -1038,6 +1052,18 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, // TODO(b/31632518) gnssHal = IGnss::getService(); if (gnssHal != nullptr) { + gnssHalDeathRecipient = new GnssDeathRecipient(); + hardware::Return<bool> linked = gnssHal->linkToDeath( + gnssHalDeathRecipient, /*cookie*/ 0); + if (!linked.isOk()) { + ALOGE("Transaction error in linking to GnssHAL death: %s", + linked.description().c_str()); + } else if (!linked) { + ALOGW("Unable to link to GnssHal death notifications"); + } else { + ALOGD("Link to death notification successful"); + } + auto gnssXtra = gnssHal->getExtensionXtra(); if (!gnssXtra.isOk()) { ALOGD("Unable to get a handle to Xtra"); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index bfa1b9988b2f..e82ba9cee919 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -742,8 +742,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean forceEphemeralUsers = false; // Can only be set by a device owner. boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner. - // one notification after enabling + 3 more after reboots - static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 4; + // one notification after enabling + one more after reboots + static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2; int numNetworkLoggingNotifications = 0; long lastNetworkLoggingNotificationTimeMs = 0; // Time in milliseconds since epoch diff --git a/services/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/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java new file mode 100644 index 000000000000..24cb72e8b0fb --- /dev/null +++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.notification; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.os.UserHandle; +import android.service.notification.StatusBarNotification; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class GlobalSortKeyComparatorTest { + + private final String PKG = "PKG"; + private final int UID = 1111111; + private static final String TEST_CHANNEL_ID = "test_channel_id"; + + @Test + public void testComparator() throws Exception { + Notification n = new Notification.Builder( + InstrumentationRegistry.getContext(), TEST_CHANNEL_ID) + .build(); + NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + left.setGlobalSortKey("first"); + + NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + right.setGlobalSortKey("second"); + + NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + + + final List<NotificationRecord> expected = new ArrayList<>(); + expected.add(left); + expected.add(right); + expected.add(last); + + List<NotificationRecord> actual = new ArrayList<>(); + actual.addAll(expected); + Collections.shuffle(actual); + + Collections.sort(actual, new GlobalSortKeyComparator()); + + assertEquals(expected, actual); + } + + @Test + public void testNoCrash_leftNull() throws Exception { + Notification n = new Notification.Builder( + InstrumentationRegistry.getContext(), TEST_CHANNEL_ID) + .build(); + NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + + NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + right.setGlobalSortKey("not null"); + + final List<NotificationRecord> expected = new ArrayList<>(); + expected.add(right); + expected.add(left); + + List<NotificationRecord> actual = new ArrayList<>(); + actual.addAll(expected); + Collections.shuffle(actual); + + Collections.sort(actual, new GlobalSortKeyComparator()); + + assertEquals(expected, actual); + } + + @Test + public void testNoCrash_rightNull() throws Exception { + Notification n = new Notification.Builder( + InstrumentationRegistry.getContext(), TEST_CHANNEL_ID) + .build(); + NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + left.setGlobalSortKey("not null"); + + NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(), + new StatusBarNotification(PKG, + PKG, 1, "media", UID, UID, n, + new UserHandle(UserHandle.myUserId()), + "", 1499), getDefaultChannel()); + + final List<NotificationRecord> expected = new ArrayList<>(); + expected.add(left); + expected.add(right); + + List<NotificationRecord> actual = new ArrayList<>(); + actual.addAll(expected); + Collections.shuffle(actual); + + Collections.sort(actual, new GlobalSortKeyComparator()); + + assertEquals(expected, actual); + } + + private NotificationChannel getDefaultChannel() { + return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name", + NotificationManager.IMPORTANCE_LOW); + } +} diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java index f666727ec1d1..57ee928f7682 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -49,6 +49,7 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.graphics.Color; import android.os.Binder; +import android.os.Process; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; @@ -460,10 +461,10 @@ public class NotificationManagerServiceTest { mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2))); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(channel2), + eq(Process.myUserHandle()), eq(channel2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -481,10 +482,10 @@ public class NotificationManagerServiceTest { mBinderService.createNotificationChannelGroups(PKG, new ParceledListSlice(Arrays.asList(group1, group2))); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(group1), + eq(Process.myUserHandle()), eq(group1), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(group2), + eq(Process.myUserHandle()), eq(group2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -503,7 +504,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -520,7 +521,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId()); verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -537,7 +538,7 @@ public class NotificationManagerServiceTest { reset(mNotificationListeners); mBinderService.deleteNotificationChannelGroup(PKG, ncg.getId()); verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), - eq(ncg), + eq(Process.myUserHandle()), eq(ncg), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -550,12 +551,12 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); mBinderService.updateNotificationChannelFromPrivilegedListener( - null, PKG, mTestNotificationChannel); + null, PKG, Process.myUserHandle(), mTestNotificationChannel); verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any()); verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -568,7 +569,7 @@ public class NotificationManagerServiceTest { try { mBinderService.updateNotificationChannelFromPrivilegedListener( - null, PKG, mTestNotificationChannel); + null, PKG, Process.myUserHandle(), mTestNotificationChannel); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass @@ -577,7 +578,33 @@ public class NotificationManagerServiceTest { verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), - eq(mTestNotificationChannel), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), + eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); + } + + @Test + @UiThreadTest + public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List<String> associations = new ArrayList<>(); + associations.add("a"); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.updateNotificationChannelFromPrivilegedListener( + null, PKG, UserHandle.ALL, mTestNotificationChannel); + fail("incorrectly allowed a change to a user listener cannot see"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); + + verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), + eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -589,7 +616,8 @@ public class NotificationManagerServiceTest { associations.add("a"); when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); - mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); verify(mRankingHelper, times(1)).getNotificationChannels( anyString(), anyInt(), anyBoolean()); @@ -603,7 +631,8 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); try { - mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass @@ -615,13 +644,37 @@ public class NotificationManagerServiceTest { @Test @UiThreadTest + public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List<String> associations = new ArrayList<>(); + associations.add("a"); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.getNotificationChannelsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listener getting channels from a user they cannot see"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).getNotificationChannels( + anyString(), anyInt(), anyBoolean()); + } + + @Test + @UiThreadTest public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); associations.add("a"); when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); - mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); verify(mRankingHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt()); } @@ -634,7 +687,29 @@ public class NotificationManagerServiceTest { when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); try { - mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG); + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); + fail("listeners that don't have a companion device shouldn't be able to call this"); + } catch (SecurityException e) { + // pass + } + + verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt()); + } + + @Test + @UiThreadTest + public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { + mNotificationManagerService.setRankingHelper(mRankingHelper); + List<String> associations = new ArrayList<>(); + when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + mListener = mock(ManagedServices.ManagedServiceInfo.class); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + try { + mBinderService.getNotificationChannelGroupsFromPrivilegedListener( + null, PKG, Process.myUserHandle()); fail("listeners that don't have a companion device shouldn't be able to call this"); } catch (SecurityException e) { // pass diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java index 946044d57e03..b2e6ef9f817f 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java @@ -124,6 +124,9 @@ public class NotificationRecordTest { builder.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES); channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES); } + } else { + channel.setSound(null, null); + builder.setSound(null, null); } if (buzzy) { if (defaultVibration) { @@ -206,6 +209,18 @@ public class NotificationRecordTest { } @Test + public void testSound_noSound_preUpgrade() throws Exception { + // pre upgrade, default sound. + StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /*defaultLights */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); + assertEquals(null, record.getSound()); + assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes()); + } + + @Test public void testSound_default_upgradeUsesChannel() throws Exception { channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES); // post upgrade, default sound. diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java new file mode 100644 index 000000000000..243c1b379608 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java @@ -0,0 +1,76 @@ +/* + * 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.server.am; + +import android.content.Context; +import android.os.Handler; +import android.support.test.InstrumentationRegistry; +import android.support.test.annotation.UiThreadTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.server.AppOpsService; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; + +/** + * runtest -c com.android.server.am.AppErrorDialogTest frameworks-services + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class AppErrorDialogTest { + + private Context mContext; + private ActivityManagerService mService; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + mService = new ActivityManagerService(new ActivityManagerService.Injector() { + @Override + public AppOpsService getAppOpsService(File file, Handler handler) { + return null; + } + + @Override + public Handler getUiHandler(ActivityManagerService service) { + return null; + } + + @Override + public boolean isNetworkRestrictedForUid(int uid) { + return false; + } + }); + } + + @Test + @UiThreadTest + public void testCreateWorks() throws Exception { + AppErrorDialog.Data data = new AppErrorDialog.Data(); + data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345); + data.result = new AppErrorResult(); + + AppErrorDialog dialog = new AppErrorDialog(mContext, mService, data); + + dialog.create(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java new file mode 100644 index 000000000000..8f2f34ee77d9 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -0,0 +1,89 @@ +/* + * 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.server.pm; + +import android.content.IIntentReceiver; + +import android.os.Bundle; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import java.io.File; + +// runtest -c com.android.server.pm.PackageManagerServiceTest frameworks-services + +@SmallTest +public class PackageManagerServiceTest extends AndroidTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testPackageRemoval() throws Exception { + class PackageSenderImpl implements PackageSender { + public void sendPackageBroadcast(final String action, final String pkg, + final Bundle extras, final int flags, final String targetPkg, + final IIntentReceiver finishedReceiver, final int[] userIds) { + } + + public void sendPackageAddedForNewUsers(String packageName, + boolean isSystem, int appId, int... userIds) { + } + } + + PackageSenderImpl sender = new PackageSenderImpl(); + PackageSetting setting = null; + PackageManagerService.PackageRemovedInfo pri = + new PackageManagerService.PackageRemovedInfo(sender); + + // Initial conditions: nothing there + assertNull(pri.removedUsers); + assertNull(pri.broadcastUsers); + + // populateUsers with nothing leaves nothing + pri.populateUsers(null, setting); + assertNull(pri.broadcastUsers); + + // Create a real (non-null) PackageSetting and confirm that the removed + // users are copied properly + setting = new PackageSetting("name", "realName", new File("codePath"), + new File("resourcePath"), "legacyNativeLibraryPathString", + "primaryCpuAbiString", "secondaryCpuAbiString", + "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0, + null, null); + pri.populateUsers(new int[] {1, 2, 3, 4, 5}, setting); + assertNotNull(pri.broadcastUsers); + assertEquals(5, pri.broadcastUsers.length); + + // Exclude a user + pri.broadcastUsers = null; + final int EXCLUDED_USER_ID = 4; + setting.setInstantApp(true, EXCLUDED_USER_ID); + pri.populateUsers(new int[] {1, 2, 3, EXCLUDED_USER_ID, 5}, setting); + assertNotNull(pri.broadcastUsers); + assertEquals(5 - 1, pri.broadcastUsers.length); + + // TODO: test that sendApplicationHiddenForUser() actually fills in + // broadcastUsers + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java index 85dc7125e3cc..7f150a21a20e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -16,6 +16,11 @@ package com.android.server.wm; +import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; +import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START; +import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState; + import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Rect; @@ -47,6 +52,12 @@ import com.android.server.wm.BoundsAnimationController.BoundsAnimator; * Test class for {@link BoundsAnimationController} to ensure that it sends the right callbacks * depending on the various interactions. * + * We are really concerned about only three of the transition states [F = fullscreen, !F = floating] + * F->!F, !F->!F, and !F->F. Each animation can only be cancelled from the target mid-transition, + * or if a new animation starts on the same target. The tests below verifies that the target is + * notified of all the cases where it is animating and cancelled so that it can respond + * appropriately. + * * Build/Install/Run: * bit FrameworksServicesTests:com.android.server.wm.BoundsAnimationControllerTests */ @@ -109,47 +120,46 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { /** * A test animate bounds user to track callbacks from the bounds animation. */ - private class TestAnimateBoundsUser implements BoundsAnimationController.AnimateBoundsUser { + private class TestBoundsAnimationTarget implements BoundsAnimationTarget { + boolean mAwaitingAnimationStart; boolean mMovedToFullscreen; boolean mAnimationStarted; - boolean mAnimationStartedToFullscreen; + boolean mSchedulePipModeChangedOnStart; boolean mAnimationEnded; - boolean mUpdatedPictureInPictureModeWithBounds; + Rect mAnimationEndFinalStackBounds; + boolean mSchedulePipModeChangedOnEnd; boolean mBoundsUpdated; + boolean mCancelRequested; Rect mStackBounds; Rect mTaskBounds; - boolean mRequestCancelAnimation = false; - - void reinitialize(Rect stackBounds, Rect taskBounds) { + void initialize(Rect from) { + mAwaitingAnimationStart = true; mMovedToFullscreen = false; mAnimationStarted = false; - mAnimationStartedToFullscreen = false; mAnimationEnded = false; - mUpdatedPictureInPictureModeWithBounds = false; - mStackBounds = stackBounds; - mTaskBounds = taskBounds; + mAnimationEndFinalStackBounds = null; + mSchedulePipModeChangedOnStart = false; + mSchedulePipModeChangedOnEnd = false; + mStackBounds = from; + mTaskBounds = null; mBoundsUpdated = false; - mRequestCancelAnimation = false; } @Override - public void onAnimationStart(boolean toFullscreen) { + public void onAnimationStart(boolean schedulePipModeChangedCallback) { + mAwaitingAnimationStart = false; mAnimationStarted = true; - mAnimationStartedToFullscreen = toFullscreen; - } - - @Override - public void updatePictureInPictureMode(Rect targetStackBounds) { - mUpdatedPictureInPictureModeWithBounds = true; + mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback; } @Override public boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds) { // TODO: Once we break the runs apart, we should fail() here if this is called outside // of onAnimationStart() and onAnimationEnd() - if (mRequestCancelAnimation) { + if (mCancelRequested) { + mCancelRequested = false; return false; } else { mBoundsUpdated = true; @@ -160,32 +170,206 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { } @Override - public void onAnimationEnd() { + public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackBounds, + boolean moveToFullscreen) { mAnimationEnded = true; + mAnimationEndFinalStackBounds = finalStackBounds; + mSchedulePipModeChangedOnEnd = schedulePipModeChangedCallback; + mMovedToFullscreen = moveToFullscreen; + mTaskBounds = null; } + } - @Override - public void moveToFullscreen() { - mMovedToFullscreen = true; + /** + * Drives the animations, makes common assertions along the way. + */ + private class BoundsAnimationDriver { + + private BoundsAnimationController mController; + private TestBoundsAnimationTarget mTarget; + private BoundsAnimator mAnimator; + + private Rect mFrom; + private Rect mTo; + private Rect mLargerBounds; + private Rect mExpectedFinalBounds; + + BoundsAnimationDriver(BoundsAnimationController controller, + TestBoundsAnimationTarget target) { + mController = controller; + mTarget = target; + } + + BoundsAnimationDriver start(Rect from, Rect to) { + if (mAnimator != null) { + throw new IllegalArgumentException("Call restart() to restart an animation"); + } + + mTarget.initialize(from); + + // Started, not running + assertTrue(mTarget.mAwaitingAnimationStart); + assertTrue(!mTarget.mAnimationStarted); + + startImpl(from, to); + + // Started and running + assertTrue(!mTarget.mAwaitingAnimationStart); + assertTrue(mTarget.mAnimationStarted); + + return this; + } + + BoundsAnimationDriver restart(Rect to) { + if (mAnimator == null) { + throw new IllegalArgumentException("Call start() to start a new animation"); + } + + BoundsAnimator oldAnimator = mAnimator; + boolean toSameBounds = mAnimator.isStarted() && to.equals(mTo); + + // Reset the animation start state + mTarget.mAnimationStarted = false; + + // Start animation + startImpl(mTarget.mStackBounds, to); + + if (toSameBounds) { + // Same animator if same final bounds + assertSame(oldAnimator, mAnimator); + } + + // No animation start for replacing animation + assertTrue(!mTarget.mAnimationStarted); + mTarget.mAnimationStarted = true; + return this; + } + + private BoundsAnimationDriver startImpl(Rect from, Rect to) { + boolean fromFullscreen = from.equals(BOUNDS_FULL); + boolean toFullscreen = to.equals(BOUNDS_FULL); + mFrom = new Rect(from); + mTo = new Rect(to); + mExpectedFinalBounds = new Rect(to); + mLargerBounds = getLargerBounds(mFrom, mTo); + + // Start animation + final @SchedulePipModeChangedState int schedulePipModeChangedState = toFullscreen + ? SCHEDULE_PIP_MODE_CHANGED_ON_START + : fromFullscreen + ? SCHEDULE_PIP_MODE_CHANGED_ON_END + : NO_PIP_MODE_CHANGED_CALLBACKS; + mAnimator = mController.animateBoundsImpl(mTarget, from, to, DURATION, + schedulePipModeChangedState, toFullscreen); + + // Original stack bounds, frozen task bounds + assertEquals(mFrom, mTarget.mStackBounds); + assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); + + // Animating to larger size + if (mFrom.equals(mLargerBounds)) { + assertTrue(!mAnimator.animatingToLargerSize()); + } else if (mTo.equals(mLargerBounds)) { + assertTrue(mAnimator.animatingToLargerSize()); + } + + return this; + } + + BoundsAnimationDriver expectStarted(boolean schedulePipModeChanged) { + // Callback made + assertTrue(mTarget.mAnimationStarted); + + assertEquals(schedulePipModeChanged, mTarget.mSchedulePipModeChangedOnStart); + return this; + } + + BoundsAnimationDriver update(float t) { + mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(t)); + + // Temporary stack bounds, frozen task bounds + if (t == 0f) { + assertEquals(mFrom, mTarget.mStackBounds); + } else if (t == 1f) { + assertEquals(mTo, mTarget.mStackBounds); + } else { + assertNotEquals(mFrom, mTarget.mStackBounds); + assertNotEquals(mTo, mTarget.mStackBounds); + } + assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds); + return this; + } + + BoundsAnimationDriver cancel() { + // Cancel + mTarget.mCancelRequested = true; + mTarget.mBoundsUpdated = false; + mExpectedFinalBounds = null; + + // Update + mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(0.5f)); + + // Not started, not running, cancel reset + assertTrue(!mTarget.mCancelRequested); + + // Stack/task bounds not updated + assertTrue(!mTarget.mBoundsUpdated); + + // Callback made + assertTrue(mTarget.mAnimationEnded); + assertNull(mTarget.mAnimationEndFinalStackBounds); + + return this; + } + + BoundsAnimationDriver end() { + mAnimator.end(); + + // Final stack bounds + assertEquals(mTo, mTarget.mStackBounds); + assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds); + assertNull(mTarget.mTaskBounds); + + return this; + } + + BoundsAnimationDriver expectEnded(boolean schedulePipModeChanged, + boolean moveToFullscreen) { + // Callback made + assertTrue(mTarget.mAnimationEnded); + + assertEquals(schedulePipModeChanged, mTarget.mSchedulePipModeChangedOnEnd); + assertEquals(moveToFullscreen, mTarget.mMovedToFullscreen); + return this; + } + + private Rect getLargerBounds(Rect r1, Rect r2) { + int r1Area = r1.width() * r1.height(); + int r2Area = r2.width() * r2.height(); + if (r1Area <= r2Area) { + return r2; + } else { + return r1; + } } } // Constants + private static final boolean SCHEDULE_PIP_MODE_CHANGED = true; private static final boolean MOVE_TO_FULLSCREEN = true; + private static final int DURATION = 100; // Some dummy bounds to represent fullscreen and floating bounds private static final Rect BOUNDS_FULL = new Rect(0, 0, 100, 100); - private static final Rect BOUNDS_FLOATING = new Rect(80, 80, 95, 95); - private static final Rect BOUNDS_ALT_FLOATING = new Rect(60, 60, 95, 95); - - // Some dummy duration - private static final int DURATION = 100; + private static final Rect BOUNDS_FLOATING = new Rect(60, 60, 95, 95); + private static final Rect BOUNDS_SMALLER_FLOATING = new Rect(80, 80, 95, 95); // Common - private MockAppTransition mAppTransition; - private MockValueAnimator mAnimator; - private TestAnimateBoundsUser mTarget; + private MockAppTransition mMockAppTransition; + private MockValueAnimator mMockAnimator; + private TestBoundsAnimationTarget mTarget; private BoundsAnimationController mController; + private BoundsAnimationDriver mDriver; // Temp private Rect mTmpRect = new Rect(); @@ -196,153 +380,184 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { final Context context = InstrumentationRegistry.getTargetContext(); final Handler handler = new Handler(Looper.getMainLooper()); - mAppTransition = new MockAppTransition(context); - mAnimator = new MockValueAnimator(); - mTarget = new TestAnimateBoundsUser(); - mController = new BoundsAnimationController(context, mAppTransition, handler); + mMockAppTransition = new MockAppTransition(context); + mMockAnimator = new MockValueAnimator(); + mTarget = new TestBoundsAnimationTarget(); + mController = new BoundsAnimationController(context, mMockAppTransition, handler); + mDriver = new BoundsAnimationDriver(mController, mTarget); } + /** BASE TRANSITIONS **/ + @UiThreadTest @Test public void testFullscreenToFloatingTransition() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Assert that when we are started, and that we are not going to fullscreen - assertTrue(mTarget.mAnimationStarted); - assertFalse(mTarget.mAnimationStartedToFullscreen); - // Ensure we are not triggering a PiP mode change - assertFalse(mTarget.mUpdatedPictureInPictureModeWithBounds); - // Ensure that the task stack bounds are already frozen to the larger source stack bounds - assertEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Drive some animation updates, ensure that only the stack bounds change and the task - // bounds are frozen to the original stack bounds (adjusted for the offset) - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - assertNotEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(1f)); - assertNotEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Finish the animation, ensure that it reaches the final bounds with the given state - boundsAnimator.end(); - assertTrue(mTarget.mAnimationEnded); - assertEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertNull(mTarget.mTaskBounds); + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); } @UiThreadTest @Test public void testFloatingToFullscreenTransition() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FLOATING, - BOUNDS_FULL, DURATION, MOVE_TO_FULLSCREEN); - - // Assert that when we are started, and that we are going to fullscreen - assertTrue(mTarget.mAnimationStarted); - assertTrue(mTarget.mAnimationStartedToFullscreen); - // Ensure that we update the PiP mode change with the new fullscreen bounds - assertTrue(mTarget.mUpdatedPictureInPictureModeWithBounds); - // Ensure that the task stack bounds are already frozen to the larger target stack bounds - assertEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Drive some animation updates, ensure that only the stack bounds change and the task - // bounds are frozen to the original stack bounds (adjusted for the offset) - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - assertNotEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(1f)); - assertNotEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertEquals(BOUNDS_FULL, offsetToZero(mTarget.mTaskBounds)); - - // Finish the animation, ensure that it reaches the final bounds with the given state - boundsAnimator.end(); - assertTrue(mTarget.mAnimationEnded); - assertEquals(BOUNDS_FULL, mTarget.mStackBounds); - assertNull(mTarget.mTaskBounds); + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFloatingToSmallerFloatingTransition() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFloatingToLargerFloatingTransition() throws Exception { + mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0f) + .update(0.5f) + .update(1f) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + /** F->!F w/ CANCEL **/ + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromAnimationToSameBounds() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_FLOATING) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_SMALLER_FLOATING) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception { + mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_FULL) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN); + } + + /** !F->F w/ CANCEL **/ + + @UiThreadTest + @Test + public void testFloatingToFullscreenCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + @UiThreadTest + @Test + public void testFloatingToFullscreenCancelFromAnimationToSameBounds() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_FULL) + .end() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN); } @UiThreadTest @Test - public void testInterruptAnimationFromUser() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Cancel the animation on the next update from the user - mTarget.mRequestCancelAnimation = true; - mTarget.mBoundsUpdated = false; - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - // Ensure that we got no more updates after returning false and the bounds are not updated - // to the end value - assertFalse(mTarget.mBoundsUpdated); - assertNotEquals(BOUNDS_FLOATING, mTarget.mStackBounds); - assertNotEquals(BOUNDS_FLOATING, mTarget.mTaskBounds); - // Ensure that we received the animation end call - assertTrue(mTarget.mAnimationEnded); + public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) + .expectStarted(SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .restart(BOUNDS_SMALLER_FLOATING) + .end() + .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); } + /** !F->!F w/ CANCEL **/ + @UiThreadTest @Test - public void testCancelAnimationFromNewAnimationToExistingBounds() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Drive some animation updates - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - - // Cancel the animation as a restart to the same bounds - mTarget.reinitialize(null, null); - final BoundsAnimator altBoundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - // Ensure the animator is the same - assertSame(boundsAnimator, altBoundsAnimator); - // Ensure we haven't restarted or finished the animation - assertFalse(mTarget.mAnimationStarted); - assertFalse(mTarget.mAnimationEnded); - // Ensure that we haven't tried to update the PiP mode - assertFalse(mTarget.mUpdatedPictureInPictureModeWithBounds); + public void testFloatingToSmallerFloatingCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); } @UiThreadTest @Test - public void testCancelAnimationFromNewAnimationToNewBounds() throws Exception { - // Create and start the animation - mTarget.reinitialize(BOUNDS_FULL, null); - final BoundsAnimator boundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - - // Drive some animation updates - boundsAnimator.onAnimationUpdate(mAnimator.getWithValue(0.5f)); - - // Cancel the animation as a restart to new bounds - mTarget.reinitialize(null, null); - final BoundsAnimator altBoundsAnimator = mController.animateBoundsImpl(mTarget, BOUNDS_FULL, - BOUNDS_ALT_FLOATING, DURATION, !MOVE_TO_FULLSCREEN); - // Ensure the animator is not the same - assertNotSame(boundsAnimator, altBoundsAnimator); - // Ensure that we did not get an animation start/end callback - assertFalse(mTarget.mAnimationStarted); - assertFalse(mTarget.mAnimationEnded); - // Ensure that we haven't tried to update the PiP mode - assertFalse(mTarget.mUpdatedPictureInPictureModeWithBounds); + public void testFloatingToLargerFloatingCancelFromTarget() throws Exception { + mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) + .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) + .update(0.25f) + .cancel() + .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN); + } + + /** MISC **/ + + @UiThreadTest + @Test + public void testBoundsAreCopied() throws Exception { + Rect from = new Rect(0, 0, 100, 100); + Rect to = new Rect(25, 25, 75, 75); + mDriver.start(from, to) + .update(0.25f) + .end(); + assertEquals(new Rect(0, 0, 100, 100), from); + assertEquals(new Rect(25, 25, 75, 75), to); } /** - * @return the bounds offset to zero/zero. + * @return whether the task and stack bounds would be the same if they were at the same offset. */ - private Rect offsetToZero(Rect bounds) { - mTmpRect.set(bounds); - mTmpRect.offsetTo(0, 0); - return mTmpRect; + private boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) { + mTmpRect.set(taskBounds); + mTmpRect.offsetTo(stackBounds.left, stackBounds.top); + return stackBounds.equals(mTmpRect); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index 0270bb955988..837ce563d616 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; @@ -289,6 +290,24 @@ public class DisplayContentTests extends WindowTestsBase { verifySizes(sDisplayContent, smallerWidth, smallerHeight, smallerDensity); } + /** + * This test enforces that the pinned stack is always kept as the top stack. + */ + @Test + public void testPinnedStackLocation() { + createStackControllerOnStackOnDisplay(PINNED_STACK_ID, sDisplayContent); + final int initialStackCount = sDisplayContent.getStackCount(); + // Ensure that the pinned stack was placed at the end + assertEquals(initialStackCount - 1, sDisplayContent.getStaskPosById(PINNED_STACK_ID)); + // By default, this should try to create a new stack on top + createTaskStackOnDisplay(sDisplayContent); + final int afterStackCount = sDisplayContent.getStackCount(); + // Make sure the stack count has increased + assertEquals(initialStackCount + 1, afterStackCount); + // Ensure that the pinned stack is still on top + assertEquals(afterStackCount - 1, sDisplayContent.getStaskPosById(PINNED_STACK_ID)); + } + private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth, int expectedBaseHeight, int expectedBaseDensity) { assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth); diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java index 5ad7f8042c01..094c7bd89ba0 100644 --- a/services/usage/java/com/android/server/usage/StorageStatsService.java +++ b/services/usage/java/com/android/server/usage/StorageStatsService.java @@ -35,6 +35,7 @@ import android.os.FileUtils; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.ParcelableException; import android.os.StatFs; import android.os.SystemProperties; import android.os.UserHandle; @@ -150,7 +151,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { try { return mInstaller.isQuotaSupported(volumeUuid); } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } } @@ -163,7 +164,8 @@ public class StorageStatsService extends IStorageStatsManager.Stub { } else { final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid); if (vol == null) { - throw new IllegalStateException("Volume was unexpected null"); + throw new ParcelableException( + new IOException("Failed to find storage device for UUID " + volumeUuid)); } return FileUtils.roundStorageSize(vol.disk.size); } @@ -189,7 +191,8 @@ public class StorageStatsService extends IStorageStatsManager.Stub { } else { final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid); if (vol == null) { - throw new IllegalStateException("Volume was unexpected null"); + throw new ParcelableException( + new IOException("Failed to find storage device for UUID " + volumeUuid)); } return vol.getPath().getUsableSpace() + cacheBytes; } @@ -221,7 +224,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { appInfo = mPackage.getApplicationInfoAsUser(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); } catch (NameNotFoundException e) { - throw new IllegalStateException(e); + throw new ParcelableException(e); } if (mPackage.getPackagesForUid(appInfo.uid).length == 1) { @@ -239,7 +242,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { mInstaller.getAppSize(volumeUuid, packageNames, userId, 0, appId, ceDataInodes, codePaths, stats); } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } return translate(stats); } @@ -265,7 +268,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { codePaths[i] = mPackage.getApplicationInfoAsUser(packageNames[i], PackageManager.MATCH_UNINSTALLED_PACKAGES, userId).getCodePath(); } catch (NameNotFoundException e) { - throw new IllegalStateException(e); + throw new ParcelableException(e); } } @@ -281,7 +284,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { checkEquals("UID " + uid, manualStats, stats); } } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } return translate(stats); } @@ -313,7 +316,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { checkEquals("User " + userId, manualStats, stats); } } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } return translate(stats); } @@ -336,7 +339,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { checkEquals("External " + userId, manualStats, stats); } } catch (InstallerException e) { - throw new IllegalStateException(e); + throw new ParcelableException(new IOException(e.getMessage())); } final ExternalStorageStats res = new ExternalStorageStats(); diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 1874d8d04723..0342da7aa6ef 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -112,20 +112,26 @@ public class TelecomManager { "android.telecom.action.CHANGE_PHONE_ACCOUNTS"; /** - * The {@link android.content.Intent} action used indicate that a new phone account was - * just registered. - * @hide + * {@link android.content.Intent} action used indicate that a new phone account was just + * registered. + * <p> + * The Intent {@link Intent#getExtras() extras} will contain {@link #EXTRA_PHONE_ACCOUNT_HANDLE} + * to indicate which {@link PhoneAccount} was registered. + * <p> + * Will only be sent to the default dialer app (see {@link #getDefaultDialerPackage()}). */ - @SystemApi public static final String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED"; /** - * The {@link android.content.Intent} action used indicate that a phone account was - * just unregistered. - * @hide + * {@link android.content.Intent} action used indicate that a phone account was just + * unregistered. + * <p> + * The Intent {@link Intent#getExtras() extras} will contain {@link #EXTRA_PHONE_ACCOUNT_HANDLE} + * to indicate which {@link PhoneAccount} was unregistered. + * <p> + * Will only be sent to the default dialer app (see {@link #getDefaultDialerPackage()}). */ - @SystemApi public static final String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED"; diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java index 943a6cade853..eeaf2c121a75 100644 --- a/telephony/java/android/telephony/Telephony.java +++ b/telephony/java/android/telephony/Telephony.java @@ -19,18 +19,21 @@ package android.provider; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; +import android.app.job.JobService; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; +import android.database.ContentObserver; import android.database.sqlite.SqliteWrapper; import android.net.Uri; +import android.telephony.Rlog; +import android.telephony.ServiceState; import android.telephony.SmsMessage; import android.telephony.SubscriptionManager; import android.text.TextUtils; -import android.telephony.Rlog; import android.util.Patterns; import com.android.internal.telephony.PhoneConstants; @@ -44,7 +47,7 @@ import java.util.regex.Pattern; /** * The Telephony provider contains data related to phone operation, specifically SMS and MMS - * messages and access to the APN list, including the MMSC to use. + * messages, access to the APN list, including the MMSC to use, and the service state. * * <p class="note"><strong>Note:</strong> These APIs are not available on all Android-powered * devices. If your app depends on telephony features such as for managing SMS messages, include @@ -2972,4 +2975,272 @@ public final class Telephony { CMAS_CERTAINTY }; } + + /** + * Constants for interfacing with the ServiceStateProvider and the different fields of the + * {@link ServiceState} class accessible through the provider. + */ + public static final class ServiceStateTable { + + /** + * Not instantiable. + * @hide + */ + private ServiceStateTable() {} + + /** + * The authority string for the ServiceStateProvider + */ + public static final String AUTHORITY = "service-state"; + + /** + * The {@code content://} style URL for the ServiceStateProvider + */ + public static final Uri CONTENT_URI = Uri.parse("content://service-state/"); + + /** + * Generates a content {@link Uri} used to receive updates on a specific field in the + * ServiceState provider. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * {@link ServiceState} while your app is running. You can also use a {@link JobService} to + * ensure your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * + * @param subId the subId to receive updates on + * @param field the ServiceState field to receive updates on + * @return the Uri used to observe {@link ServiceState} changes + */ + public static Uri getUriForSubIdAndField(int subId, String field) { + return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId)) + .appendEncodedPath(field).build(); + } + + /** + * Generates a content {@link Uri} used to receive updates on every field in the + * ServiceState provider. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * {@link ServiceState} while your app is running. You can also use a {@link JobService} to + * ensure your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * + * @param subId the subId to receive updates on + * @return the Uri used to observe {@link ServiceState} changes + */ + public static Uri getUriForSubId(int subId) { + return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId)).build(); + } + + /** + * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance. + * + * @param state the ServiceState to convert into ContentValues + * @return the convertedContentValues instance + * @hide + */ + public static ContentValues getContentValuesForServiceState(ServiceState state) { + ContentValues values = new ContentValues(); + values.put(VOICE_REG_STATE, state.getVoiceRegState()); + values.put(DATA_REG_STATE, state.getDataRegState()); + values.put(VOICE_ROAMING_TYPE, state.getVoiceRoamingType()); + values.put(DATA_ROAMING_TYPE, state.getDataRoamingType()); + values.put(VOICE_OPERATOR_ALPHA_LONG, state.getVoiceOperatorAlphaLong()); + values.put(VOICE_OPERATOR_ALPHA_SHORT, state.getVoiceOperatorAlphaShort()); + values.put(VOICE_OPERATOR_NUMERIC, state.getVoiceOperatorNumeric()); + values.put(DATA_OPERATOR_ALPHA_LONG, state.getDataOperatorAlphaLong()); + values.put(DATA_OPERATOR_ALPHA_SHORT, state.getDataOperatorAlphaShort()); + values.put(DATA_OPERATOR_NUMERIC, state.getDataOperatorNumeric()); + values.put(IS_MANUAL_NETWORK_SELECTION, state.getIsManualSelection()); + values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology()); + values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology()); + values.put(CSS_INDICATOR, state.getCssIndicator()); + values.put(NETWORK_ID, state.getNetworkId()); + values.put(SYSTEM_ID, state.getSystemId()); + values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator()); + values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator()); + values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex()); + values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode()); + values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly()); + values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration()); + values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation()); + return values; + } + + /** + * An integer value indicating the current voice service state. + * <p> + * Valid values: {@link ServiceState#STATE_IN_SERVICE}, + * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY}, + * {@link ServiceState#STATE_POWER_OFF}. + * <p> + * This is the same as {@link ServiceState#getState()}. + */ + public static final String VOICE_REG_STATE = "voice_reg_state"; + + /** + * An integer value indicating the current data service state. + * <p> + * Valid values: {@link ServiceState#STATE_IN_SERVICE}, + * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY}, + * {@link ServiceState#STATE_POWER_OFF}. + * <p> + * This is the same as {@link ServiceState#getDataRegState()}. + * @hide + */ + public static final String DATA_REG_STATE = "data_reg_state"; + + /** + * An integer value indicating the current voice roaming type. + * <p> + * This is the same as {@link ServiceState#getVoiceRoamingType()}. + * @hide + */ + public static final String VOICE_ROAMING_TYPE = "voice_roaming_type"; + + /** + * An integer value indicating the current data roaming type. + * <p> + * This is the same as {@link ServiceState#getDataRoamingType()}. + * @hide + */ + public static final String DATA_ROAMING_TYPE = "data_roaming_type"; + + /** + * The current registered voice network operator name in long alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getVoiceOperatorAlphaLong()}. + * @hide + */ + public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long"; + + /** + * The current registered operator name in short alphanumeric format. + * <p> + * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice + * network operator name in long alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getVoiceOperatorAlphaShort()}. + * @hide + */ + public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short"; + + + /** + * The current registered operator numeric id. + * <p> + * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit + * network code. + * <p> + * This is the same as {@link ServiceState#getOperatorNumeric()}. + */ + public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; + + /** + * The current registered data network operator name in long alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getDataOperatorAlphaLong()}. + * @hide + */ + public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long"; + + /** + * The current registered data network operator name in short alphanumeric format. + * <p> + * This is the same as {@link ServiceState#getDataOperatorAlphaShort()}. + * @hide + */ + public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short"; + + /** + * The current registered data network operator numeric id. + * <p> + * This is the same as {@link ServiceState#getDataOperatorNumeric()}. + * @hide + */ + public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric"; + + /** + * The current network selection mode. + * <p> + * This is the same as {@link ServiceState#getIsManualSelection()}. + */ + public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + + /** + * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}. + * @hide + */ + public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology"; + + /** + * This is the same as {@link ServiceState#getRilDataRadioTechnology()}. + * @hide + */ + public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology"; + + /** + * This is the same as {@link ServiceState#getCssIndicator()}. + * @hide + */ + public static final String CSS_INDICATOR = "css_indicator"; + + /** + * This is the same as {@link ServiceState#getNetworkId()}. + * @hide + */ + public static final String NETWORK_ID = "network_id"; + + /** + * This is the same as {@link ServiceState#getSystemId()}. + * @hide + */ + public static final String SYSTEM_ID = "system_id"; + + /** + * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}. + * @hide + */ + public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator"; + + /** + * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}. + * @hide + */ + public static final String CDMA_DEFAULT_ROAMING_INDICATOR = + "cdma_default_roaming_indicator"; + + /** + * This is the same as {@link ServiceState#getCdmaEriIconIndex()}. + * @hide + */ + public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index"; + + /** + * This is the same as {@link ServiceState#getCdmaEriIconMode()}. + * @hide + */ + public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode"; + + /** + * This is the same as {@link ServiceState#isEmergencyOnly()}. + * @hide + */ + public static final String IS_EMERGENCY_ONLY = "is_emergency_only"; + + /** + * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}. + * @hide + */ + public static final String IS_DATA_ROAMING_FROM_REGISTRATION = + "is_data_roaming_from_registration"; + + /** + * This is the same as {@link ServiceState#isUsingCarrierAggregation()}. + * @hide + */ + public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation"; + } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 397aa0020d13..3d51c4cd51ae 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -4393,7 +4393,7 @@ public class TelephonyManager { * Returns null if the query fails. * * - * <p>Requires that the caller has READ_PRIVILEGED_PHONE_STATE + * <p>Requires that the caller has READ_PHONE_STATE * * @return an array of forbidden PLMNs or null if not available */ @@ -4406,7 +4406,7 @@ public class TelephonyManager { * Returns null if the query fails. * * - * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE + * <p>Requires that the calling app has READ_PHONE_STATE * * @param subId subscription ID used for authentication * @param appType the icc application type, like {@link #APPTYPE_USIM} diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index a8eb9862202d..b4e3a476425a 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -530,13 +530,6 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } - /** STOPSHIP remove when trial API is turned down */ - @Override - public ComponentName startServiceInForeground(Intent service, - int id, Notification notification) { - throw new UnsupportedOperationException(); - } - @Override public boolean stopService(Intent service) { throw new UnsupportedOperationException(); @@ -554,13 +547,6 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } - /** @hide STOPSHIP removed when trial API is turned down */ - @Override - public ComponentName startServiceInForegroundAsUser(Intent service, - int id, Notification notification, UserHandle user) { - throw new UnsupportedOperationException(); - } - /** @hide */ @Override public boolean stopServiceAsUser(Intent service, UserHandle user) { diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 960a2d9fd726..20392e733599 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -1126,4 +1126,12 @@ public class MockPackageManager extends PackageManager { public ComponentName getInstantAppResolverSettingsComponent() { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public ComponentName getInstantAppInstallerComponent() { + throw new UnsupportedOperationException(); + } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c562cb95ee31..6140a896b1a8 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -23,7 +23,12 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.NetworkCapabilities.*; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.app.NotificationManager; import android.app.PendingIntent; @@ -33,6 +38,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.PacketKeepalive; @@ -42,6 +48,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 +58,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,24 +73,32 @@ 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; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; +import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPolicyManagerInternal; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; @@ -134,8 +151,19 @@ public class ConnectivityServiceTest extends AndroidTestCase { private class MockContext extends BroadcastInterceptingContext { private final MockContentResolver mContentResolver; + @Spy private Resources mResources; + MockContext(Context base) { super(base); + + mResources = spy(base.getResources()); + when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)). + thenReturn(new String[] { + "wifi,1,1,1,-1,true", + "mobile,0,0,0,-1,true", + "mobile_mms,2,0,2,60000,true", + }); + mContentResolver = new MockContentResolver(); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); } @@ -151,6 +179,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { public ContentResolver getContentResolver() { return mContentResolver; } + + @Override + public Resources getResources() { + return mResources; + } } /** @@ -319,6 +352,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); @@ -621,6 +659,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { private class WrappedConnectivityService extends ConnectivityService { public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker; private WrappedNetworkMonitor mLastCreatedNetworkMonitor; + private MockableSystemProperties mSystemProperties; public WrappedConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, @@ -630,9 +669,13 @@ public class ConnectivityServiceTest extends AndroidTestCase { } @Override - protected int getDefaultTcpRwnd() { - // Prevent wrapped ConnectivityService from trying to write to SystemProperties. - return 0; + protected MockableSystemProperties getSystemProperties() { + // Minimal approach to overriding system properties: let most calls fall through to real + // device values, and only override ones values that are important to this test. + mSystemProperties = spy(new MockableSystemProperties()); + when(mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0); + when(mSystemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false); + return mSystemProperties; } @Override @@ -805,6 +848,14 @@ public class ConnectivityServiceTest extends AndroidTestCase { return cv; } + public void testNetworkTypes() { + // Ensure that our mocks for the networkAttributes config variable work as expected. If they + // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types + // will fail. Failing here is much easier to debug. + assertTrue(mCm.isNetworkSupported(TYPE_WIFI)); + assertTrue(mCm.isNetworkSupported(TYPE_MOBILE)); + } + @SmallTest public void testLingering() throws Exception { verifyNoNetwork(); @@ -1819,34 +1870,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; - assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER", - execptionCalled); + 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 + } + + 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 diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 328fc0a1eaeb..1e77ac170028 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -1865,13 +1865,6 @@ public class BridgeContext extends Context { } @Override - public ComponentName startServiceInForeground(Intent service, - int id, Notification notification) { - // pass - return null; - } - - @Override public boolean stopService(Intent arg0) { // pass return false; @@ -1884,13 +1877,6 @@ public class BridgeContext extends Context { } @Override - public ComponentName startServiceInForegroundAsUser(Intent service, - int id, Notification notification, UserHandle user) { - // pass - return null; - } - - @Override public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) { // pass return false; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index 5a239e1f3f38..ad26bc8b8672 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -923,4 +923,9 @@ public class BridgePackageManager extends PackageManager { public ComponentName getInstantAppResolverSettingsComponent() { return null; } + + @Override + public ComponentName getInstantAppInstallerComponent() { + return null; + } } diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java index 82b3792a331c..bf5c42b8ca1c 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java @@ -19,6 +19,7 @@ package android.net.wifi.aware; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.NetworkSpecifier; import android.net.wifi.RttManager; import android.util.Log; @@ -250,8 +251,8 @@ public class DiscoverySession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * unencrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an unencrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -276,13 +277,13 @@ public class DiscoverySession { * request from only that peer. A RESPONDER may specify a {@code null} - * indicating that it will accept connection requests from any device. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) { + public NetworkSpecifier createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) { if (mTerminated) { Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session"); return null; @@ -302,8 +303,8 @@ public class DiscoverySession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -329,14 +330,14 @@ public class DiscoverySession { * {@link #createNetworkSpecifierOpen(PeerHandle)} API to * specify an open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierPassphrase(@Nullable PeerHandle peerHandle, - @NonNull String passphrase) { + public NetworkSpecifier createNetworkSpecifierPassphrase( + @Nullable PeerHandle peerHandle, @NonNull String passphrase) { if (passphrase == null || passphrase.length() == 0) { throw new IllegalArgumentException("Passphrase must not be null or empty"); } @@ -361,8 +362,8 @@ public class DiscoverySession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -389,8 +390,8 @@ public class DiscoverySession { * Passphrase or {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an * open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. @@ -398,7 +399,7 @@ public class DiscoverySession { * @hide */ @SystemApi - public String createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle, + public NetworkSpecifier createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle, @NonNull byte[] pmk) { if (pmk == null || pmk.length == 0) { throw new IllegalArgumentException("PMK must not be null or empty"); diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 4d3957aece91..3fcbd4b60259 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -24,6 +24,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; import android.net.wifi.RttManager; import android.os.Binder; import android.os.Bundle; @@ -31,7 +32,6 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.util.Base64; import android.util.Log; import android.util.SparseArray; @@ -39,9 +39,6 @@ import com.android.internal.annotations.GuardedBy; import libcore.util.HexEncoding; -import org.json.JSONException; -import org.json.JSONObject; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -129,65 +126,6 @@ public class WifiAwareManager { private static final boolean VDBG = false; // STOPSHIP if true /** - * Keys used to generate a Network Specifier for the Aware network request. The network - * specifier is formatted as a JSON string. - */ - - /** - * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk/passphrase optional - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_IB = 0; - - /** - * TYPE: in band, any peer: role, client_id, session_id, pmk/passphrase optional - * [only permitted for RESPONDER] - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1; - - /** - * TYPE: out-of-band: role, client_id, peer_mac, pmk/passphrase optional - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_OOB = 2; - - /** - * TYPE: out-of-band, any peer: role, client_id, pmk/passphrase optional - * [only permitted for RESPONDER] - * @hide - */ - public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3; - - - /** @hide */ - public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_TYPE = "type"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_ROLE = "role"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_CLIENT_ID = "client_id"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_SESSION_ID = "session_id"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PEER_ID = "peer_id"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PMK = "pmk"; - - /** @hide */ - public static final String NETWORK_SPECIFIER_KEY_PASSPHRASE = "passphrase"; - - /** * Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed. * Use the {@link #isAvailable()} to query the current status. * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering @@ -483,7 +421,7 @@ public class WifiAwareManager { } /** @hide */ - public String createNetworkSpecifier(int clientId, int role, int sessionId, + public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId, PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId @@ -492,9 +430,6 @@ public class WifiAwareManager { + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); } - int type = (peerHandle == null) ? NETWORK_SPECIFIER_TYPE_IB_ANY_PEER - : NETWORK_SPECIFIER_TYPE_IB; - if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { throw new IllegalArgumentException( @@ -509,35 +444,20 @@ public class WifiAwareManager { } } - JSONObject json; - try { - json = new JSONObject(); - json.put(NETWORK_SPECIFIER_KEY_TYPE, type); - json.put(NETWORK_SPECIFIER_KEY_ROLE, role); - json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId); - json.put(NETWORK_SPECIFIER_KEY_SESSION_ID, sessionId); - if (peerHandle != null) { - json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId); - } - if (pmk == null) { - pmk = new byte[0]; - } - json.put(NETWORK_SPECIFIER_KEY_PMK, - Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT)); - if (passphrase == null) { - passphrase = new String(); - } - json.put(NETWORK_SPECIFIER_KEY_PASSPHRASE, passphrase); - - } catch (JSONException e) { - return ""; - } - - return json.toString(); + return new WifiAwareNetworkSpecifier( + (peerHandle == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER + : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, + role, + clientId, + sessionId, + peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID + null, // peerMac (not used in this method) + pmk, + passphrase); } /** @hide */ - public String createNetworkSpecifier(int clientId, @DataPathRole int role, + public NetworkSpecifier createNetworkSpecifier(int clientId, @DataPathRole int role, @Nullable byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { Log.v(TAG, "createNetworkSpecifier: role=" + role @@ -545,9 +465,6 @@ public class WifiAwareManager { + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); } - int type = (peer == null) ? - NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER : NETWORK_SPECIFIER_TYPE_OOB; - if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { throw new IllegalArgumentException( @@ -564,29 +481,16 @@ public class WifiAwareManager { throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address"); } - JSONObject json; - try { - json = new JSONObject(); - json.put(NETWORK_SPECIFIER_KEY_TYPE, type); - json.put(NETWORK_SPECIFIER_KEY_ROLE, role); - json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId); - if (peer != null) { - json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer))); - } - if (pmk == null) { - pmk = new byte[0]; - } - json.put(NETWORK_SPECIFIER_KEY_PMK, - Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT)); - if (passphrase == null) { - passphrase = new String(); - } - json.put(NETWORK_SPECIFIER_KEY_PASSPHRASE, passphrase); - } catch (JSONException e) { - return ""; - } - - return json.toString(); + return new WifiAwareNetworkSpecifier( + (peer == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER + : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB, + role, + clientId, + 0, // 0 is an invalid session ID + 0, // 0 is an invalid peer ID + peer, + pmk, + passphrase); } private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub { diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java new file mode 100644 index 000000000000..59934806f398 --- /dev/null +++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.aware; + +import android.net.NetworkSpecifier; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Network specifier object used to request a Wi-Fi Aware network. Apps do not create these objects + * directly but obtain them using + * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} or + * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)} or their secure (Passphrase) + * versions. + * + * @hide + */ +public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable { + /** + * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk/passphrase optional + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_IB = 0; + + /** + * TYPE: in band, any peer: role, client_id, session_id, pmk/passphrase optional + * [only permitted for RESPONDER] + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1; + + /** + * TYPE: out-of-band: role, client_id, peer_mac, pmk/passphrase optional + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_OOB = 2; + + /** + * TYPE: out-of-band, any peer: role, client_id, pmk/passphrase optional + * [only permitted for RESPONDER] + * @hide + */ + public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3; + + /** @hide */ + public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER; + + /** + * One of the NETWORK_SPECIFIER_TYPE_* constants. The type of the network specifier object. + * @hide + */ + public final int type; + + /** + * The role of the device: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR or + * WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER. + * @hide + */ + public final int role; + + /** + * The client ID of the device. + * @hide + */ + public final int clientId; + + /** + * The session ID in which context to request a data-path. Only relevant for IB requests. + * @hide + */ + public final int sessionId; + + /** + * The peer ID of the device which the data-path should be connected to. Only relevant for + * IB requests (i.e. not IB_ANY_PEER or OOB*). + * @hide + */ + public final int peerId; + + /** + * The peer MAC address of the device which the data-path should be connected to. Only relevant + * for OB requests (i.e. not OOB_ANY_PEER or IB*). + * @hide + */ + public final byte[] peerMac; + + /** + * The PMK of the requested data-path. Can be null. Only one or none of pmk or passphrase should + * be specified. + * @hide + */ + public final byte[] pmk; + + /** + * The Passphrase of the requested data-path. Can be null. Only one or none of the pmk or + * passphrase should be specified. + * @hide + */ + public final String passphrase; + + /** @hide */ + public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId, + byte[] peerMac, byte[] pmk, String passphrase) { + this.type = type; + this.role = role; + this.clientId = clientId; + this.sessionId = sessionId; + this.peerId = peerId; + this.peerMac = peerMac; + this.pmk = pmk; + this.passphrase = passphrase; + } + + public static final Creator<WifiAwareNetworkSpecifier> CREATOR = + new Creator<WifiAwareNetworkSpecifier>() { + @Override + public WifiAwareNetworkSpecifier createFromParcel(Parcel in) { + return new WifiAwareNetworkSpecifier( + in.readInt(), // type + in.readInt(), // role + in.readInt(), // clientId + in.readInt(), // sessionId + in.readInt(), // peerId + in.createByteArray(), // peerMac + in.createByteArray(), // pmk + in.readString()); // passphrase + } + + @Override + public WifiAwareNetworkSpecifier[] newArray(int size) { + return new WifiAwareNetworkSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(type); + dest.writeInt(role); + dest.writeInt(clientId); + dest.writeInt(sessionId); + dest.writeInt(peerId); + dest.writeByteArray(peerMac); + dest.writeByteArray(pmk); + dest.writeString(passphrase); + } + + /** @hide */ + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + // MatchAllNetworkSpecifier is taken care in NetworkCapabilities#satisfiedBySpecifier. + return equals(other); + } + + /** @hide */ + @Override + public int hashCode() { + int result = 17; + + result = 31 * result + type; + result = 31 * result + role; + result = 31 * result + clientId; + result = 31 * result + sessionId; + result = 31 * result + peerId; + result = 31 * result + Arrays.hashCode(peerMac); + result = 31 * result + Arrays.hashCode(pmk); + result = 31 * result + Objects.hashCode(passphrase); + + return result; + } + + /** @hide */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof WifiAwareNetworkSpecifier)) { + return false; + } + + WifiAwareNetworkSpecifier lhs = (WifiAwareNetworkSpecifier) obj; + + return type == lhs.type + && role == lhs.role + && clientId == lhs.clientId + && sessionId == lhs.sessionId + && peerId == lhs.peerId + && Arrays.equals(peerMac, lhs.peerMac) + && Arrays.equals(pmk, lhs.pmk) + && Objects.equals(passphrase, lhs.passphrase); + } + + /** @hide */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("WifiAwareNetworkSpecifier ["); + sb.append("type=").append(type) + .append(", role=").append(role) + .append(", clientId=").append(clientId) + .append(", sessionId=").append(sessionId) + .append(", peerId=").append(peerId) + // masking potential PII (although low impact information) + .append(", peerMac=").append((peerMac == null) ? "<null>" : "<non-null>") + // masking PII + .append(", pmk=").append((pmk == null) ? "<null>" : "<non-null>") + // masking PII + .append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>") + .append("]"); + return sb.toString(); + } +} diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java index 895defb9a540..ac3a6bba052c 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java @@ -19,6 +19,7 @@ package android.net.wifi.aware; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.NetworkSpecifier; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -184,8 +185,8 @@ public class WifiAwareSession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * unencrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an unencrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -205,29 +206,29 @@ public class WifiAwareSession { * peer. A RESPONDER may specify a {@code null} - indicating that it will accept * connection requests from any device. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierOpen(@WifiAwareManager.DataPathRole int role, - @Nullable byte[] peer) { + public NetworkSpecifier createNetworkSpecifierOpen( + @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager"); - return ""; + return null; } if (mTerminated) { Log.e(TAG, "createNetworkSpecifierOpen: called after termination"); - return ""; + return null; } return mgr.createNetworkSpecifier(mClientId, role, peer, null, null); } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -247,22 +248,23 @@ public class WifiAwareSession { * the passphrase. Use {@link #createNetworkSpecifierOpen(int, byte[])} to * specify an open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public String createNetworkSpecifierPassphrase(@WifiAwareManager.DataPathRole int role, - @Nullable byte[] peer, @NonNull String passphrase) { + public NetworkSpecifier createNetworkSpecifierPassphrase( + @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, + @NonNull String passphrase) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierPassphrase: called post GC on WifiAwareManager"); - return ""; + return null; } if (mTerminated) { Log.e(TAG, "createNetworkSpecifierPassphrase: called after termination"); - return ""; + return null; } if (passphrase == null || passphrase.length() == 0) { throw new IllegalArgumentException("Passphrase must not be null or empty"); @@ -271,8 +273,8 @@ public class WifiAwareSession { } /** - * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an - * encrypted WiFi Aware connection (link) to the specified peer. The + * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for + * an encrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <p> @@ -294,8 +296,8 @@ public class WifiAwareSession { * Passphrase or {@link #createNetworkSpecifierOpen(int, byte[])} to specify an * open (unencrypted) link. * - * @return A string to be used to construct - * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to + * @return A {@link NetworkSpecifier} to be used to construct + * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest, * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. @@ -303,16 +305,16 @@ public class WifiAwareSession { * @hide */ @SystemApi - public String createNetworkSpecifierPmk(@WifiAwareManager.DataPathRole int role, - @Nullable byte[] peer, @NonNull byte[] pmk) { + public NetworkSpecifier createNetworkSpecifierPmk( + @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, @NonNull byte[] pmk) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager"); - return ""; + return null; } if (mTerminated) { Log.e(TAG, "createNetworkSpecifierPmk: called after termination"); - return ""; + return null; } if (pmk == null || pmk.length == 0) { throw new IllegalArgumentException("PMK must not be null or empty"); diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 830db22929e8..72a6a7a7b46b 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -34,11 +34,9 @@ import android.os.IBinder; import android.os.Parcel; import android.os.test.TestLooper; import android.test.suitebuilder.annotation.SmallTest; -import android.util.Base64; import libcore.util.HexEncoding; -import org.json.JSONObject; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -959,8 +957,6 @@ public class WifiAwareManagerTest { final ConfigRequest configRequest = new ConfigRequest.Builder().build(); final PublishConfig publishConfig = new PublishConfig.Builder().build(); - String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT); - ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass( WifiAwareSession.class); ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor @@ -991,51 +987,37 @@ public class WifiAwareManagerTest { inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture()); // (3) request an open (unencrypted) network specifier from the session - String networkSpecifier = publishSession.getValue().createNetworkSpecifierOpen(peerHandle); + WifiAwareNetworkSpecifier ns = + (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierOpen( + peerHandle); // validate format - JSONObject jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("session_id", sessionId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); - collector.checkThat("peer_id", peerHandle.peerId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); + collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); // (4) request an encrypted (PMK) network specifier from the session - networkSpecifier = publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk); + ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk( + peerHandle, pmk); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("session_id", sessionId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); - collector.checkThat("peer_id", peerHandle.peerId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); - collector.checkThat("pmk", pmkB64 , - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); + collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); + collector.checkThat("pmk", pmk , equalTo(ns.pmk)); // (5) request an encrypted (Passphrase) network specifier from the session - networkSpecifier = publishSession.getValue().createNetworkSpecifierPassphrase(peerHandle, - passphrase); + ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPassphrase( + peerHandle, passphrase); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("session_id", sessionId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); - collector.checkThat("peer_id", peerHandle.peerId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); - collector.checkThat("passphrase", passphrase, - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PASSPHRASE))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); + collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); + collector.checkThat("passphrase", passphrase, equalTo(ns.passphrase)); verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService, mockPublishSession, mockRttListener); @@ -1054,8 +1036,6 @@ public class WifiAwareManagerTest { final byte[] pmk = "Some arbitrary pmk data".getBytes(); final String passphrase = "A really bad password"; - String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT); - ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass( WifiAwareSession.class); ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor @@ -1074,47 +1054,32 @@ public class WifiAwareManagerTest { WifiAwareSession session = sessionCaptor.getValue(); // (2) request an open (unencrypted) direct network specifier - String networkSpecifier = session.createNetworkSpecifierOpen(role, someMac); + WifiAwareNetworkSpecifier ns = + (WifiAwareNetworkSpecifier) session.createNetworkSpecifierOpen(role, someMac); // validate format - JSONObject jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( - jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), - false))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); // (3) request an encrypted (PMK) direct network specifier - networkSpecifier = session.createNetworkSpecifierPmk(role, someMac, pmk); + ns = (WifiAwareNetworkSpecifier) session.createNetworkSpecifierPmk(role, someMac, pmk); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( - jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), - false))); - collector.checkThat("pmk", pmkB64, - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); + collector.checkThat("pmk", pmk, equalTo(ns.pmk)); // (4) request an encrypted (Passphrase) direct network specifier - networkSpecifier = session.createNetworkSpecifierPassphrase(role, someMac, passphrase); + ns = (WifiAwareNetworkSpecifier) session.createNetworkSpecifierPassphrase(role, someMac, + passphrase); // validate format - jsonObject = new JSONObject(networkSpecifier); - collector.checkThat("role", role, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); - collector.checkThat("client_id", clientId, - equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); - collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( - jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), - false))); - collector.checkThat("passphrase", passphrase, - equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PASSPHRASE))); + collector.checkThat("role", role, equalTo(ns.role)); + collector.checkThat("client_id", clientId, equalTo(ns.clientId)); + collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); + collector.checkThat("passphrase", passphrase, equalTo(ns.passphrase)); verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService, mockPublishSession, mockRttListener); |