diff options
401 files changed, 6586 insertions, 6163 deletions
diff --git a/Android.bp b/Android.bp index 6a85f62a5ae6..b4110fa906cf 100644 --- a/Android.bp +++ b/Android.bp @@ -480,10 +480,7 @@ java_defaults { "media/java/android/media/IMediaHTTPConnection.aidl", "media/java/android/media/IMediaHTTPService.aidl", "media/java/android/media/IMediaResourceMonitor.aidl", - "media/java/android/media/IMediaRoute2Callback.aidl", - "media/java/android/media/IMediaRoute2Provider.aidl", "media/java/android/media/IMediaRouterClient.aidl", - "media/java/android/media/IMediaRouter2ManagerClient.aidl", "media/java/android/media/IMediaRouterService.aidl", "media/java/android/media/IMediaScannerListener.aidl", "media/java/android/media/IMediaScannerService.aidl", @@ -923,6 +920,7 @@ filegroup { "core/java/com/android/internal/util/RingBufferIndices.java", "core/java/com/android/internal/util/State.java", "core/java/com/android/internal/util/StateMachine.java", + "core/java/com/android/internal/util/TrafficStatsConstants.java", "core/java/com/android/internal/util/WakeupMessage.java", "core/java/android/net/shared/*.java", ] @@ -1836,4 +1834,4 @@ aidl_mapping { name: "framework-aidl-mappings", srcs: [":framework-defaults"], output: "framework-aidl-mappings.txt" -} +}
\ No newline at end of file diff --git a/api/current.txt b/api/current.txt index 7878eb63b035..8ec7594773af 100644 --- a/api/current.txt +++ b/api/current.txt @@ -224,6 +224,7 @@ package android { field public static final int __removed3 = 16844187; // 0x101059b field public static final int __removed4 = 16844188; // 0x101059c field public static final int __removed5 = 16844189; // 0x101059d + field public static final int __removed6 = 16844182; // 0x1010596 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -734,6 +735,7 @@ package android { field public static final int iconTintMode = 16844127; // 0x101055f field public static final int iconifiedByDefault = 16843514; // 0x10102fa field public static final int id = 16842960; // 0x10100d0 + field public static final int identifier = 16844204; // 0x10105ac field public static final int ignoreGravity = 16843263; // 0x10101ff field public static final int imageButtonStyle = 16842866; // 0x1010072 field public static final int imageWellStyle = 16842867; // 0x1010073 @@ -749,7 +751,6 @@ package android { field public static final int immersive = 16843456; // 0x10102c0 field public static final int importantForAccessibility = 16843690; // 0x10103aa field public static final int importantForAutofill = 16844120; // 0x1010558 - field public static final int importantForContentCapture = 16844182; // 0x1010596 field public static final int inAnimation = 16843127; // 0x1010177 field public static final int includeFontPadding = 16843103; // 0x101015f field public static final int includeInGlobalSearch = 16843374; // 0x101026e @@ -6234,14 +6235,14 @@ package android.app { } public class TaskInfo { - field public android.content.ComponentName baseActivity; - field public android.content.Intent baseIntent; + field @Nullable public android.content.ComponentName baseActivity; + field @NonNull public android.content.Intent baseIntent; field public boolean isRunning; field public int numActivities; - field public android.content.ComponentName origActivity; - field public android.app.ActivityManager.TaskDescription taskDescription; + field @Nullable public android.content.ComponentName origActivity; + field @Nullable public android.app.ActivityManager.TaskDescription taskDescription; field public int taskId; - field public android.content.ComponentName topActivity; + field @Nullable public android.content.ComponentName topActivity; } public class TaskStackBuilder { @@ -9000,7 +9001,7 @@ package android.bluetooth.le { method @Nullable public byte[] getManufacturerSpecificData(int); method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData(); method @Nullable public byte[] getServiceData(android.os.ParcelUuid); - method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); + method @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public int getTxPowerLevel(); } @@ -10085,6 +10086,7 @@ package android.content { method public int getFlags(); method @Nullable public float[] getFloatArrayExtra(String); method public float getFloatExtra(String, float); + method @Nullable public String getIdentifier(); method @Nullable public int[] getIntArrayExtra(String); method public int getIntExtra(String, int); method @Nullable public java.util.ArrayList<java.lang.Integer> getIntegerArrayListExtra(String); @@ -10168,6 +10170,7 @@ package android.content { method @NonNull public android.content.Intent setDataAndTypeAndNormalize(@NonNull android.net.Uri, @Nullable String); method public void setExtrasClassLoader(@Nullable ClassLoader); method @NonNull public android.content.Intent setFlags(int); + method @NonNull public android.content.Intent setIdentifier(@Nullable String); method @NonNull public android.content.Intent setPackage(@Nullable String); method public void setSelector(@Nullable android.content.Intent); method public void setSourceBounds(@Nullable android.graphics.Rect); @@ -10428,6 +10431,7 @@ package android.content { field public static final int FILL_IN_CLIP_DATA = 128; // 0x80 field public static final int FILL_IN_COMPONENT = 8; // 0x8 field public static final int FILL_IN_DATA = 2; // 0x2 + field public static final int FILL_IN_IDENTIFIER = 256; // 0x100 field public static final int FILL_IN_PACKAGE = 16; // 0x10 field public static final int FILL_IN_SELECTOR = 64; // 0x40 field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20 @@ -23041,6 +23045,7 @@ package android.media { public final class AudioAttributes implements android.os.Parcelable { method public boolean areHapticChannelsMuted(); method public int describeContents(); + method public int getAllowedCapturePolicy(); method public int getContentType(); method public int getFlags(); method public int getUsage(); @@ -23246,6 +23251,7 @@ package android.media { method public int generateAudioSessionId(); method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations(); method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations(); + method public int getAllowedCapturePolicy(); method public android.media.AudioDeviceInfo[] getDevices(int); method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException; method public int getMode(); @@ -23418,6 +23424,10 @@ package android.media { } public final class AudioPlaybackCaptureConfiguration { + method @NonNull public int[] getExcludeUids(); + method @NonNull public int[] getExcludeUsages(); + method @NonNull public int[] getMatchingUids(); + method @NonNull public int[] getMatchingUsages(); method @NonNull public android.media.projection.MediaProjection getMediaProjection(); } @@ -23776,27 +23786,6 @@ package android.media { field public static final int QUALITY_MEDIUM = 1; // 0x1 } - public class DataSourceDesc { - method public long getEndPosition(); - method @Nullable public String getMediaId(); - method public long getStartPosition(); - field public static final long LONG_MAX_TIME_MS = 576460752303423L; // 0x20c49ba5e353fL - field public static final long POSITION_UNKNOWN = 576460752303423L; // 0x20c49ba5e353fL - } - - public static final class DataSourceDesc.Builder { - ctor public DataSourceDesc.Builder(); - ctor public DataSourceDesc.Builder(@Nullable android.media.DataSourceDesc); - method @NonNull public android.media.DataSourceDesc build(); - method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.net.Uri); - method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>); - method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor); - method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long); - method @NonNull public android.media.DataSourceDesc.Builder setEndPosition(long); - method @NonNull public android.media.DataSourceDesc.Builder setMediaId(@Nullable String); - method @NonNull public android.media.DataSourceDesc.Builder setStartPosition(long); - } - public final class DeniedByServerException extends android.media.MediaDrmException { ctor public DeniedByServerException(String); } @@ -24663,8 +24652,6 @@ package android.media { } public class MediaController2 implements java.lang.AutoCloseable { - ctor public MediaController2(@NonNull android.content.Context, @NonNull android.media.Session2Token); - ctor public MediaController2(@NonNull android.content.Context, @NonNull android.media.Session2Token, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaController2.ControllerCallback); method public void cancelSessionCommand(@NonNull Object); method public void close(); method @Nullable public android.media.Session2Token getConnectedSessionToken(); @@ -24672,6 +24659,13 @@ package android.media { method @NonNull public Object sendSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle); } + public static final class MediaController2.Builder { + ctor public MediaController2.Builder(@NonNull android.content.Context, @NonNull android.media.Session2Token); + method @NonNull public android.media.MediaController2 build(); + method @NonNull public android.media.MediaController2.Builder setConnectionHints(@NonNull android.os.Bundle); + method @NonNull public android.media.MediaController2.Builder setControllerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaController2.ControllerCallback); + } + public abstract static class MediaController2.ControllerCallback { ctor public MediaController2.ControllerCallback(); method public void onCommandResult(@NonNull android.media.MediaController2, @NonNull Object, @NonNull android.media.Session2Command, @NonNull android.media.Session2Command.Result); @@ -25144,25 +25138,6 @@ package android.media { field public static final int TYPE_STRING = 4; // 0x4 } - public final class MediaItem2 implements android.os.Parcelable { - method public int describeContents(); - method public long getEndPosition(); - method @Nullable public android.media.MediaMetadata getMetadata(); - method public long getStartPosition(); - method public void setMetadata(@Nullable android.media.MediaMetadata); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.MediaItem2> CREATOR; - field public static final long POSITION_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL - } - - public static final class MediaItem2.Builder { - ctor public MediaItem2.Builder(); - method @NonNull public android.media.MediaItem2 build(); - method @NonNull public android.media.MediaItem2.Builder setEndPosition(long); - method @NonNull public android.media.MediaItem2.Builder setMetadata(@Nullable android.media.MediaMetadata); - method @NonNull public android.media.MediaItem2.Builder setStartPosition(long); - } - public final class MediaMetadata implements android.os.Parcelable { method public boolean containsKey(String); method public int describeContents(); @@ -25555,225 +25530,6 @@ package android.media { field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1 } - public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable { - ctor public MediaPlayer2(@NonNull android.content.Context); - method public void addOnRoutingChangedListener(@NonNull android.media.AudioRouting.OnRoutingChangedListener, @Nullable android.os.Handler); - method @NonNull public Object attachAuxEffect(int); - method public boolean cancelCommand(@NonNull Object); - method public void clearDrmEventCallback(); - method @NonNull public Object clearNextDataSources(); - method public void clearPendingCommands(); - method public void close(); - method @NonNull public Object deselectTrack(@NonNull android.media.MediaPlayer2.TrackInfo); - method @NonNull public Object deselectTrack(@NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.TrackInfo); - method @NonNull public android.media.AudioAttributes getAudioAttributes(); - method public int getAudioSessionId(); - method public long getBufferedPosition(); - method public long getBufferedPosition(@NonNull android.media.DataSourceDesc); - method @Nullable public android.media.DataSourceDesc getCurrentDataSource(); - method public long getCurrentPosition(); - method public long getDuration(); - method public long getDuration(@NonNull android.media.DataSourceDesc); - method public float getMaxPlayerVolume(); - method @Nullable public android.os.PersistableBundle getMetrics(); - method @NonNull public android.media.PlaybackParams getPlaybackParams(); - method public float getPlayerVolume(); - method @Nullable public android.media.AudioDeviceInfo getPreferredDevice(); - method @Nullable public android.media.AudioDeviceInfo getRoutedDevice(); - method @Nullable public android.media.MediaPlayer2.TrackInfo getSelectedTrack(int); - method @Nullable public android.media.MediaPlayer2.TrackInfo getSelectedTrack(@NonNull android.media.DataSourceDesc, int); - method public int getState(); - method @NonNull public android.media.SyncParams getSyncParams(); - method @Nullable public android.media.MediaTimestamp getTimestamp(); - method @NonNull public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo(); - method @NonNull public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo(@NonNull android.media.DataSourceDesc); - method @NonNull public android.util.Size getVideoSize(); - method public boolean isLooping(); - method @NonNull public Object loopCurrent(boolean); - method @NonNull public Object notifyWhenCommandLabelReached(@NonNull Object); - method @NonNull public Object pause(); - method @NonNull public Object play(); - method @NonNull public Object prepare(); - method public void registerEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer2.EventCallback); - method public void removeOnRoutingChangedListener(@NonNull android.media.AudioRouting.OnRoutingChangedListener); - method public void reset(); - method @NonNull public Object seekTo(long); - method @NonNull public Object seekTo(long, int); - method @NonNull public Object selectTrack(@NonNull android.media.MediaPlayer2.TrackInfo); - method @NonNull public Object selectTrack(@NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.TrackInfo); - method @NonNull public Object setAudioAttributes(@NonNull android.media.AudioAttributes); - method @NonNull public Object setAudioSessionId(int); - method @NonNull public Object setAuxEffectSendLevel(float); - method @NonNull public Object setDataSource(@NonNull android.media.DataSourceDesc); - method @NonNull public Object setDisplay(@Nullable android.view.SurfaceHolder); - method public void setDrmEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer2.DrmEventCallback); - method @NonNull public Object setNextDataSource(@NonNull android.media.DataSourceDesc); - method @NonNull public Object setNextDataSources(@NonNull java.util.List<android.media.DataSourceDesc>); - method @NonNull public Object setPlaybackParams(@NonNull android.media.PlaybackParams); - method @NonNull public Object setPlayerVolume(float); - method public boolean setPreferredDevice(@Nullable android.media.AudioDeviceInfo); - method @NonNull public Object setScreenOnWhilePlaying(boolean); - method @NonNull public Object setSurface(@Nullable android.view.Surface); - method @NonNull public Object setSyncParams(@NonNull android.media.SyncParams); - method @NonNull public Object setWakeLock(@NonNull android.os.PowerManager.WakeLock); - method @NonNull public Object skipToNext(); - method public void unregisterEventCallback(@NonNull android.media.MediaPlayer2.EventCallback); - field public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1; // 0x1 - field public static final int CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES = 30; // 0x1e - field public static final int CALL_COMPLETED_DESELECT_TRACK = 2; // 0x2 - field public static final int CALL_COMPLETED_LOOP_CURRENT = 3; // 0x3 - field public static final int CALL_COMPLETED_PAUSE = 4; // 0x4 - field public static final int CALL_COMPLETED_PLAY = 5; // 0x5 - field public static final int CALL_COMPLETED_PREPARE = 6; // 0x6 - field public static final int CALL_COMPLETED_SEEK_TO = 14; // 0xe - field public static final int CALL_COMPLETED_SELECT_TRACK = 15; // 0xf - field public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16; // 0x10 - field public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17; // 0x11 - field public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12 - field public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19; // 0x13 - field public static final int CALL_COMPLETED_SET_DISPLAY = 33; // 0x21 - field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22; // 0x16 - field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23; // 0x17 - field public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24; // 0x18 - field public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26; // 0x1a - field public static final int CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING = 35; // 0x23 - field public static final int CALL_COMPLETED_SET_SURFACE = 27; // 0x1b - field public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28; // 0x1c - field public static final int CALL_COMPLETED_SET_WAKE_LOCK = 34; // 0x22 - field public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29; // 0x1d - field public static final int CALL_STATUS_BAD_VALUE = 2; // 0x2 - field public static final int CALL_STATUS_ERROR_IO = 4; // 0x4 - field public static final int CALL_STATUS_ERROR_UNKNOWN = -2147483648; // 0x80000000 - field public static final int CALL_STATUS_INVALID_OPERATION = 1; // 0x1 - field public static final int CALL_STATUS_NO_DRM_SCHEME = 6; // 0x6 - field public static final int CALL_STATUS_NO_ERROR = 0; // 0x0 - field public static final int CALL_STATUS_PERMISSION_DENIED = 3; // 0x3 - field public static final int CALL_STATUS_SKIPPED = 5; // 0x5 - field public static final int MEDIA_ERROR_IO = -1004; // 0xfffffc14 - field public static final int MEDIA_ERROR_MALFORMED = -1007; // 0xfffffc11 - field public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; // 0xc8 - field public static final int MEDIA_ERROR_TIMED_OUT = -110; // 0xffffff92 - field public static final int MEDIA_ERROR_UNKNOWN = 1; // 0x1 - field public static final int MEDIA_ERROR_UNSUPPORTED = -1010; // 0xfffffc0e - field public static final int MEDIA_INFO_AUDIO_NOT_PLAYING = 804; // 0x324 - field public static final int MEDIA_INFO_AUDIO_RENDERING_START = 4; // 0x4 - field public static final int MEDIA_INFO_BAD_INTERLEAVING = 800; // 0x320 - field public static final int MEDIA_INFO_BUFFERING_END = 702; // 0x2be - field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd - field public static final int MEDIA_INFO_BUFFERING_UPDATE = 704; // 0x2c0 - field public static final int MEDIA_INFO_DATA_SOURCE_END = 5; // 0x5 - field public static final int MEDIA_INFO_DATA_SOURCE_LIST_END = 6; // 0x6 - field public static final int MEDIA_INFO_DATA_SOURCE_REPEAT = 7; // 0x7 - field public static final int MEDIA_INFO_DATA_SOURCE_START = 2; // 0x2 - field public static final int MEDIA_INFO_METADATA_UPDATE = 802; // 0x322 - field public static final int MEDIA_INFO_NOT_SEEKABLE = 801; // 0x321 - field public static final int MEDIA_INFO_PREPARED = 100; // 0x64 - field public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; // 0x386 - field public static final int MEDIA_INFO_UNKNOWN = 1; // 0x1 - field public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; // 0x385 - field public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805; // 0x325 - 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 int PLAYER_STATE_ERROR = 1005; // 0x3ed - field public static final int PLAYER_STATE_IDLE = 1001; // 0x3e9 - field public static final int PLAYER_STATE_PAUSED = 1003; // 0x3eb - field public static final int PLAYER_STATE_PLAYING = 1004; // 0x3ec - field public static final int PLAYER_STATE_PREPARED = 1002; // 0x3ea - field public static final int PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR = 7; // 0x7 - 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_RESOURCE_BUSY = 5; // 0x5 - field public static final int PREPARE_DRM_STATUS_RESTORE_ERROR = 6; // 0x6 - field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 - field public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4; // 0x4 - 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 - field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0 - } - - public abstract static class MediaPlayer2.DrmEventCallback { - ctor public MediaPlayer2.DrmEventCallback(); - method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm); - method @Nullable public abstract android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo); - method @NonNull public abstract byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest); - method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]); - } - - public static final class MediaPlayer2.DrmInfo { - method @NonNull public java.util.Map<java.util.UUID,byte[]> getPssh(); - method @NonNull public java.util.List<java.util.UUID> getSupportedSchemes(); - } - - public static final class MediaPlayer2.DrmPreparationInfo { - method @Nullable public byte[] getInitData(); - method @Nullable public byte[] getKeySetId(); - method public int getKeyType(); - method @Nullable public String getMimeType(); - method @Nullable public java.util.Map<java.lang.String,java.lang.String> getOptionalParameters(); - method @NonNull public java.util.UUID getUuid(); - } - - public static final class MediaPlayer2.DrmPreparationInfo.Builder { - ctor public MediaPlayer2.DrmPreparationInfo.Builder(@NonNull java.util.UUID); - method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo build(); - method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]); - method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]); - method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int); - method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String); - method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>); - } - - public static class MediaPlayer2.EventCallback { - ctor public MediaPlayer2.EventCallback(); - method public void onCallCompleted(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int); - method public void onCommandLabelReached(@NonNull android.media.MediaPlayer2, @NonNull Object); - method public void onError(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int); - method public void onInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int); - method public void onMediaTimeDiscontinuity(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaTimestamp); - method public void onSubtitleData(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.SubtitleData); - method public void onTimedMetaDataAvailable(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.TimedMetaData); - method public void onVideoSizeChanged(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.util.Size); - } - - public static final class MediaPlayer2.MetricsConstants { - field public static final String CODEC_AUDIO = "android.media.mediaplayer.audio.codec"; - field public static final String CODEC_VIDEO = "android.media.mediaplayer.video.codec"; - field public static final String DURATION = "android.media.mediaplayer.durationMs"; - field public static final String ERRORS = "android.media.mediaplayer.err"; - field public static final String ERROR_CODE = "android.media.mediaplayer.errcode"; - field public static final String FRAMES = "android.media.mediaplayer.frames"; - field public static final String FRAMES_DROPPED = "android.media.mediaplayer.dropped"; - field public static final String HEIGHT = "android.media.mediaplayer.height"; - field public static final String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime"; - field public static final String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime"; - field public static final String PLAYING = "android.media.mediaplayer.playingMs"; - field public static final String WIDTH = "android.media.mediaplayer.width"; - } - - public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException { - ctor public MediaPlayer2.NoDrmSchemeException(@Nullable String); - } - - public static final class MediaPlayer2.SubtitleData { - method @NonNull public byte[] getData(); - method public long getDurationUs(); - method public long getStartTimeUs(); - method @NonNull public android.media.MediaPlayer2.TrackInfo getTrackInfo(); - } - - public static class MediaPlayer2.TrackInfo { - method @Nullable public android.media.MediaFormat getFormat(); - method @NonNull public String getLanguage(); - method public int getTrackType(); - field public static final int MEDIA_TRACK_TYPE_AUDIO = 2; // 0x2 - field public static final int MEDIA_TRACK_TYPE_METADATA = 5; // 0x5 - field public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4; // 0x4 - field public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0; // 0x0 - field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1 - } - public class MediaRecorder implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection { ctor public MediaRecorder(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); @@ -26080,6 +25836,7 @@ package android.media { } public static final class MediaSession2.ControllerInfo { + method @NonNull public android.os.Bundle getConnectionHints(); method @NonNull public String getPackageName(); method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getRemoteUserInfo(); method public int getUid(); @@ -26099,7 +25856,7 @@ package android.media { method public final void addSession(@NonNull android.media.MediaSession2); method @NonNull public final java.util.List<android.media.MediaSession2> getSessions(); method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); - method @NonNull public abstract android.media.MediaSession2 onGetPrimarySession(); + method @Nullable public abstract android.media.MediaSession2 onGetSession(@NonNull android.media.MediaSession2.ControllerInfo); method @Nullable public abstract android.media.MediaSession2Service.MediaNotification onUpdateNotification(@NonNull android.media.MediaSession2); method public final void removeSession(@NonNull android.media.MediaSession2); field public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service"; @@ -26401,8 +26158,8 @@ package android.media { ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle); method public int describeContents(); method public int getCommandCode(); - method @Nullable public String getCustomCommand(); - method @Nullable public android.os.Bundle getExtras(); + method @Nullable public String getCustomAction(); + method @Nullable public android.os.Bundle getCustomExtras(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0 field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR; @@ -38582,7 +38339,6 @@ package android.provider { field public static final String ARTIST_KEY = "artist_key"; field public static final String BOOKMARK = "bookmark"; field public static final String COMPOSER = "composer"; - field public static final String DURATION = "duration"; field public static final String IS_ALARM = "is_alarm"; field public static final String IS_AUDIOBOOK = "is_audiobook"; field public static final String IS_MUSIC = "is_music"; @@ -38665,7 +38421,6 @@ package android.provider { } public static interface MediaStore.DownloadColumns extends android.provider.MediaStore.MediaColumns { - field public static final String DESCRIPTION = "description"; field public static final String DOWNLOAD_URI = "download_uri"; field public static final String REFERER_URI = "referer_uri"; } @@ -38700,16 +38455,11 @@ package android.provider { } public static interface MediaStore.Images.ImageColumns extends android.provider.MediaStore.MediaColumns { - field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; - field public static final String BUCKET_ID = "bucket_id"; - field public static final String DATE_TAKEN = "datetaken"; field public static final String DESCRIPTION = "description"; - field public static final String GROUP_ID = "group_id"; field public static final String IS_PRIVATE = "isprivate"; field @Deprecated public static final String LATITUDE = "latitude"; field @Deprecated public static final String LONGITUDE = "longitude"; field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; - field public static final String ORIENTATION = "orientation"; field @Deprecated public static final String PICASA_ID = "picasa_id"; } @@ -38753,16 +38503,22 @@ package android.provider { } public static interface MediaStore.MediaColumns extends android.provider.BaseColumns { + field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; + field public static final String BUCKET_ID = "bucket_id"; field @Deprecated public static final String DATA = "_data"; field public static final String DATE_ADDED = "date_added"; field public static final String DATE_EXPIRES = "date_expires"; field public static final String DATE_MODIFIED = "date_modified"; + field public static final String DATE_TAKEN = "datetaken"; field public static final String DISPLAY_NAME = "_display_name"; field public static final String DOCUMENT_ID = "document_id"; + field public static final String DURATION = "duration"; + field public static final String GROUP_ID = "group_id"; field public static final String HEIGHT = "height"; field public static final String INSTANCE_ID = "instance_id"; field public static final String IS_PENDING = "is_pending"; field public static final String MIME_TYPE = "mime_type"; + field public static final String ORIENTATION = "orientation"; field public static final String ORIGINAL_DOCUMENT_ID = "original_document_id"; field public static final String OWNER_PACKAGE_NAME = "owner_package_name"; field public static final String RELATIVE_PATH = "relative_path"; @@ -38811,13 +38567,8 @@ package android.provider { field public static final String ALBUM = "album"; field public static final String ARTIST = "artist"; field public static final String BOOKMARK = "bookmark"; - field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; - field public static final String BUCKET_ID = "bucket_id"; field public static final String CATEGORY = "category"; - field public static final String DATE_TAKEN = "datetaken"; field public static final String DESCRIPTION = "description"; - field public static final String DURATION = "duration"; - field public static final String GROUP_ID = "group_id"; field public static final String IS_PRIVATE = "isprivate"; field public static final String LANGUAGE = "language"; field @Deprecated public static final String LATITUDE = "latitude"; @@ -38855,6 +38606,7 @@ package android.provider { field public static final String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS"; field public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS"; field public static final String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS"; + field public static final String ACTION_APP_BATTERY_SETTINGS = "android.settings.APP_BATTERY_SETTINGS"; field public static final String ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS = "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS"; field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS"; field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS"; @@ -39326,7 +39078,7 @@ package android.provider { field @Deprecated public static final String BEARER = "bearer"; field public static final String CARRIER_ENABLED = "carrier_enabled"; field public static final String CARRIER_ID = "carrier_id"; - field public static final android.net.Uri CONTENT_URI; + field @NonNull public static final android.net.Uri CONTENT_URI; field public static final String CURRENT = "current"; field public static final String DEFAULT_SORT_ORDER = "name ASC"; field @Deprecated public static final String MCC = "mcc"; @@ -39345,7 +39097,7 @@ package android.provider { field public static final String PROXY = "proxy"; field public static final String ROAMING_PROTOCOL = "roaming_protocol"; field public static final String SERVER = "server"; - field public static final android.net.Uri SIM_APN_URI; + field @NonNull public static final android.net.Uri SIM_APN_URI; field public static final String SUBSCRIPTION_ID = "sub_id"; field public static final String TYPE = "type"; field public static final String USER = "user"; @@ -42006,7 +41758,7 @@ package android.service.voice { method public int getDisabledShowContext(); method public static boolean isActiveService(android.content.Context, android.content.ComponentName); method public android.os.IBinder onBind(android.content.Intent); - method @Nullable public java.util.Set<java.lang.String> onGetSupportedVoiceActions(@NonNull java.util.Set<java.lang.String>); + method @NonNull public java.util.Set<java.lang.String> onGetSupportedVoiceActions(@NonNull java.util.Set<java.lang.String>); method public void onLaunchVoiceAssistFromKeyguard(); method public void onReady(); method public void onShutdown(); @@ -48048,6 +47800,10 @@ package android.util { method public boolean equals(android.util.DisplayMetrics); method public void setTo(android.util.DisplayMetrics); method public void setToDefaults(); + field public static final int DENSITY_140 = 140; // 0x8c + field public static final int DENSITY_180 = 180; // 0xb4 + field public static final int DENSITY_200 = 200; // 0xc8 + field public static final int DENSITY_220 = 220; // 0xdc field public static final int DENSITY_260 = 260; // 0x104 field public static final int DENSITY_280 = 280; // 0x118 field public static final int DENSITY_300 = 300; // 0x12c @@ -50431,7 +50187,6 @@ package android.view { method @android.view.ViewDebug.CapturedViewProperty @IdRes public int getId(); method @android.view.ViewDebug.ExportedProperty(category="accessibility", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, to="noHideDescendants")}) public int getImportantForAccessibility(); method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForAutofill(); - method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForContentCapture(); method public boolean getKeepScreenOn(); method public android.view.KeyEvent.DispatcherState getKeyDispatcherState(); method @android.view.ViewDebug.ExportedProperty(category="accessibility") @IdRes public int getLabelFor(); @@ -50572,7 +50327,6 @@ package android.view { method @android.view.ViewDebug.ExportedProperty public boolean isHovered(); method public boolean isImportantForAccessibility(); method public final boolean isImportantForAutofill(); - method public final boolean isImportantForContentCapture(); method public boolean isInEditMode(); method public boolean isInLayout(); method @android.view.ViewDebug.ExportedProperty public boolean isInTouchMode(); @@ -50647,7 +50401,6 @@ package android.view { method @CallSuper public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); method public void onProvideAutofillStructure(android.view.ViewStructure, int); method public void onProvideAutofillVirtualStructure(android.view.ViewStructure, int); - method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int); method public void onProvideStructure(android.view.ViewStructure); method public void onProvideVirtualStructure(android.view.ViewStructure); method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int); @@ -50773,7 +50526,6 @@ package android.view { method public void setId(@IdRes int); method public void setImportantForAccessibility(int); method public void setImportantForAutofill(int); - method public void setImportantForContentCapture(int); method public void setKeepScreenOn(boolean); method public void setKeyboardNavigationCluster(boolean); method public void setLabelFor(@IdRes int); @@ -50952,11 +50704,6 @@ package android.view { field public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 8; // 0x8 field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1 field public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 4; // 0x4 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0; // 0x0 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 2; // 0x2 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 8; // 0x8 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 1; // 0x1 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 4; // 0x4 field public static final int INVISIBLE = 4; // 0x4 field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000 field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2 @@ -53064,7 +52811,7 @@ package android.view.contentcapture { method @Nullable public java.util.Set<android.view.contentcapture.ContentCaptureCondition> getContentCaptureConditions(); method @Nullable public android.content.ComponentName getServiceComponentName(); method public boolean isContentCaptureEnabled(); - method public void removeUserData(@NonNull android.view.contentcapture.UserDataRemovalRequest); + method public void removeData(@NonNull android.view.contentcapture.DataRemovalRequest); method public void setContentCaptureEnabled(boolean); } @@ -53075,6 +52822,7 @@ package android.view.contentcapture { method @Nullable public final android.view.contentcapture.ContentCaptureContext getContentCaptureContext(); method @NonNull public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId(); method @NonNull public android.view.autofill.AutofillId newAutofillId(@NonNull android.view.autofill.AutofillId, long); + method @NonNull public final android.view.ViewStructure newViewStructure(@NonNull android.view.View); method @NonNull public final android.view.ViewStructure newVirtualViewStructure(@NonNull android.view.autofill.AutofillId, long); method public final void notifyViewAppeared(@NonNull android.view.ViewStructure); method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId); @@ -53089,24 +52837,24 @@ package android.view.contentcapture { field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureSessionId> CREATOR; } - public final class UserDataRemovalRequest implements android.os.Parcelable { + public final class DataRemovalRequest implements android.os.Parcelable { method public int describeContents(); - method @NonNull public java.util.List<android.view.contentcapture.UserDataRemovalRequest.LocusIdRequest> getLocusIdRequests(); + method @NonNull public java.util.List<android.view.contentcapture.DataRemovalRequest.LocusIdRequest> getLocusIdRequests(); method @NonNull public String getPackageName(); method public boolean isForEverything(); method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.UserDataRemovalRequest> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.DataRemovalRequest> CREATOR; field public static final int FLAG_IS_PREFIX = 1; // 0x1 } - public static final class UserDataRemovalRequest.Builder { - ctor public UserDataRemovalRequest.Builder(); - method @NonNull public android.view.contentcapture.UserDataRemovalRequest.Builder addLocusId(@NonNull android.content.LocusId, int); - method @NonNull public android.view.contentcapture.UserDataRemovalRequest build(); - method @NonNull public android.view.contentcapture.UserDataRemovalRequest.Builder forEverything(); + public static final class DataRemovalRequest.Builder { + ctor public DataRemovalRequest.Builder(); + method @NonNull public android.view.contentcapture.DataRemovalRequest.Builder addLocusId(@NonNull android.content.LocusId, int); + method @NonNull public android.view.contentcapture.DataRemovalRequest build(); + method @NonNull public android.view.contentcapture.DataRemovalRequest.Builder forEverything(); } - public final class UserDataRemovalRequest.LocusIdRequest { + public final class DataRemovalRequest.LocusIdRequest { method @NonNull public int getFlags(); method @NonNull public android.content.LocusId getLocusId(); } @@ -53656,6 +53404,7 @@ package android.view.textclassifier { method public int describeContents(); method @Nullable public String getCallingPackageName(); method @NonNull public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation(); + method @NonNull public android.os.Bundle getExtras(); method @Nullable public java.util.List<java.lang.String> getHints(); method @IntRange(from=0xffffffff) public int getMaxSuggestions(); method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig getTypeConfig(); @@ -53668,6 +53417,7 @@ package android.view.textclassifier { public static final class ConversationActions.Request.Builder { ctor public ConversationActions.Request.Builder(@NonNull java.util.List<android.view.textclassifier.ConversationActions.Message>); method @NonNull public android.view.textclassifier.ConversationActions.Request build(); + method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setExtras(@Nullable android.os.Bundle); method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setHints(@Nullable java.util.List<java.lang.String>); method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(@IntRange(from=0xffffffff) int); method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(@Nullable android.view.textclassifier.TextClassifier.EntityConfig); diff --git a/api/removed.txt b/api/removed.txt index 70ff50ed40a6..883632623a83 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -522,6 +522,22 @@ package android.provider { method @Deprecated public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri); } + public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns { + field public static final String DURATION = "duration"; + } + + public static interface MediaStore.DownloadColumns extends android.provider.MediaStore.MediaColumns { + field @Deprecated public static final String DESCRIPTION = "description"; + } + + public static interface MediaStore.Images.ImageColumns extends android.provider.MediaStore.MediaColumns { + field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; + field public static final String BUCKET_ID = "bucket_id"; + field public static final String DATE_TAKEN = "datetaken"; + field public static final String GROUP_ID = "group_id"; + field public static final String ORIENTATION = "orientation"; + } + public static interface MediaStore.MediaColumns extends android.provider.BaseColumns { field @Deprecated public static final String HASH = "_hash"; field @Deprecated public static final String IS_TRASHED = "is_trashed"; @@ -546,6 +562,14 @@ package android.provider { method @NonNull public android.net.Uri publish(); } + public static interface MediaStore.Video.VideoColumns extends android.provider.MediaStore.MediaColumns { + field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; + field public static final String BUCKET_ID = "bucket_id"; + field public static final String DATE_TAKEN = "datetaken"; + field public static final String DURATION = "duration"; + field public static final String GROUP_ID = "group_id"; + } + public static final class Settings.Global extends android.provider.Settings.NameValueTable { field @Deprecated public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync"; } diff --git a/api/system-current.txt b/api/system-current.txt index 4da923619f36..209fca77a8ba 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -254,8 +254,6 @@ package android { field public static final int config_defaultAssistant = 17039393; // 0x1040021 field public static final int config_defaultBrowser = 17039394; // 0x1040022 field public static final int config_defaultDialer = 17039395; // 0x1040023 - field public static final int config_defaultGallery = 17039398; // 0x1040026 - field public static final int config_defaultMusic = 17039397; // 0x1040025 field public static final int config_defaultSms = 17039396; // 0x1040024 field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020 @@ -564,6 +562,7 @@ package android.app { method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]); method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getData(long); method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getMetadata(); + method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] getRegisteredExperimentIds() throws android.app.StatsManager.StatsUnavailableException; method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException; method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException; method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException; @@ -605,7 +604,7 @@ package android.app { public final class Vr2dDisplayProperties implements android.os.Parcelable { ctor public Vr2dDisplayProperties(int, int, int); method public int describeContents(); - method public void dump(java.io.PrintWriter, String); + method public void dump(@NonNull java.io.PrintWriter, @NonNull String); method public int getAddedFlags(); method public int getDpi(); method public int getHeight(); @@ -616,26 +615,26 @@ package android.app { field public static final int FLAG_VIRTUAL_DISPLAY_ENABLED = 1; // 0x1 } - public static class Vr2dDisplayProperties.Builder { + public static final class Vr2dDisplayProperties.Builder { ctor public Vr2dDisplayProperties.Builder(); - method public android.app.Vr2dDisplayProperties.Builder addFlags(int); - method public android.app.Vr2dDisplayProperties build(); - method public android.app.Vr2dDisplayProperties.Builder removeFlags(int); - method public android.app.Vr2dDisplayProperties.Builder setDimensions(int, int, int); - method public android.app.Vr2dDisplayProperties.Builder setEnabled(boolean); + method @NonNull public android.app.Vr2dDisplayProperties.Builder addFlags(int); + method @NonNull public android.app.Vr2dDisplayProperties build(); + method @NonNull public android.app.Vr2dDisplayProperties.Builder removeFlags(int); + method @NonNull public android.app.Vr2dDisplayProperties.Builder setDimensions(int, int, int); + method @NonNull public android.app.Vr2dDisplayProperties.Builder setEnabled(boolean); } public class VrManager { method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public int getVr2dDisplayId(); method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isPersistentVrModeEnabled(); method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isVrModeEnabled(); - method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void registerVrStateCallback(@NonNull java.util.concurrent.Executor, android.app.VrStateCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void registerVrStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.VrStateCallback); method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setAndBindVrCompositor(android.content.ComponentName); method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setPersistentVrModeEnabled(boolean); method @RequiresPermission("android.permission.ACCESS_VR_MANAGER") public void setStandbyEnabled(boolean); - method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties(android.app.Vr2dDisplayProperties); - method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(android.content.ComponentName); - method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void unregisterVrStateCallback(android.app.VrStateCallback); + method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties(@NonNull android.app.Vr2dDisplayProperties); + method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(@Nullable android.content.ComponentName); + method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void unregisterVrStateCallback(@NonNull android.app.VrStateCallback); } public abstract class VrStateCallback { @@ -1093,12 +1092,11 @@ package android.app.prediction { } public static final class AppTarget.Builder { - ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull String, @NonNull android.os.UserHandle); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo); method @NonNull public android.app.prediction.AppTarget build(); method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String); method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { @@ -2003,15 +2001,15 @@ package android.hardware.hdmi { public final class HdmiControlManager { method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener); method @Nullable public android.hardware.hdmi.HdmiClient getClient(int); - method @Nullable public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevicesList(); + method @NonNull public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevices(); method public int getPhysicalAddress(); method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient(); method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient(); method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient(); - method public boolean isRemoteDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo); - method public void powerOffRemoteDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method public boolean isDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method public void powerOffDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener); - method public void requestRemoteDeviceToBecomeActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method public void setActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean); field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE"; field public static final int AVR_VOLUME_MUTED = 101; // 0x65 @@ -3673,7 +3671,6 @@ package android.media.audiopolicy { method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener); method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback); method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); - method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean); method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException; } @@ -4228,9 +4225,12 @@ package android.net { method public static void setThreadStatsTagApp(); method public static void setThreadStatsTagBackup(); method public static void setThreadStatsTagRestore(); - field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40 - field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46 - field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42 + field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f + field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80 + field public static final int TAG_NETWORK_STACK_RANGE_END = -257; // 0xfffffeff + field public static final int TAG_NETWORK_STACK_RANGE_START = -768; // 0xfffffd00 + field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = -241; // 0xffffff0f + field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00 } public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable { @@ -5824,7 +5824,6 @@ package android.provider { public final class DeviceConfig { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(@NonNull String, @NonNull String, float); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(@NonNull String, @NonNull String, int); @@ -5832,7 +5831,6 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(@NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; @@ -5865,10 +5863,6 @@ package android.provider { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } - public static interface DeviceConfig.OnPropertyChangedListener { - method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); - } - public static class DeviceConfig.Properties { method public boolean getBoolean(@NonNull String, boolean); method public float getFloat(@NonNull String, float); @@ -6276,7 +6270,6 @@ package android.service.attention { public abstract class AttentionService extends android.app.Service { ctor public AttentionService(); - method public final void disableSelf(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void onCancelAttentionCheck(@NonNull android.service.attention.AttentionService.AttentionCallback); method public abstract void onCheckAttention(@NonNull android.service.attention.AttentionService.AttentionCallback); @@ -6397,9 +6390,9 @@ package android.service.contentcapture { method public void onConnected(); method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent); method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId); + method public void onDataRemovalRequest(@NonNull android.view.contentcapture.DataRemovalRequest); method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDisconnected(); - method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureConditions(@NonNull String, @Nullable java.util.Set<android.view.contentcapture.ContentCaptureCondition>); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; @@ -6499,7 +6492,7 @@ package android.service.euicc { ctor public EuiccService(); method @CallSuper public android.os.IBinder onBind(android.content.Intent); method public abstract int onDeleteSubscription(int, String); - method public abstract android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle); + method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle); method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean); method public abstract int onEraseSubscriptions(int); method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean); @@ -7206,6 +7199,7 @@ package android.telephony { } public static final class CarrierRestrictionRules.Builder { + ctor public CarrierRestrictionRules.Builder(); method @NonNull public android.telephony.CarrierRestrictionRules build(); method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed(); method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); diff --git a/api/system-removed.txt b/api/system-removed.txt index 162f212a787e..8f7112266457 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -60,6 +60,18 @@ package android.content { } +package android.hardware.hdmi { + + public final class HdmiControlManager { + method @Deprecated public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevicesList(); + method @Deprecated public boolean isRemoteDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method @Deprecated public void powerOffRemoteDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method @Deprecated public void powerOnRemoteDevice(android.hardware.hdmi.HdmiDeviceInfo); + method @Deprecated public void requestRemoteDeviceToBecomeActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + } + +} + package android.location { public class LocationManager { @@ -113,6 +125,19 @@ package android.os { } +package android.provider { + + public final class DeviceConfig { + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + } + + public static interface DeviceConfig.OnPropertyChangedListener { + method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); + } + +} + package android.service.notification { public abstract class NotificationListenerService extends android.app.Service { diff --git a/api/test-current.txt b/api/test-current.txt index ac44dca9ae5b..4bcb8da281f6 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -498,12 +498,11 @@ package android.app.prediction { } public static final class AppTarget.Builder { - ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull String, @NonNull android.os.UserHandle); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo); method @NonNull public android.app.prediction.AppTarget build(); method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String); method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { @@ -1074,6 +1073,19 @@ package android.location { package android.media { + public final class AudioFocusInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.media.AudioAttributes getAttributes(); + method @NonNull public String getClientId(); + method public int getClientUid(); + method public int getFlags(); + method public int getGainRequest(); + method public int getLossReceived(); + method @NonNull public String getPackageName(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR; + } + public final class AudioFocusRequest { method @Nullable public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener(); } @@ -1085,6 +1097,15 @@ package android.media { method public static boolean isEncodingLinearPcm(int); } + public class AudioManager { + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method public boolean hasRegisteredDynamicPolicy(); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); + } + public static final class AudioRecord.MetricsConstants { field public static final String ATTRIBUTES = "android.media.audiorecord.attributes"; field public static final String CHANNEL_MASK = "android.media.audiorecord.channelMask"; @@ -1124,13 +1145,6 @@ package android.media { method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int); } - public class FileDataSourceDesc extends android.media.DataSourceDesc { - method public long getLength(); - method public long getOffset(); - method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor(); - field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL - } - public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint { ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size); ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size); @@ -1139,28 +1153,11 @@ package android.media { method public int getMaxMacroBlocks(); } - public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable { - method public android.media.MediaPlayer2.DrmInfo getDrmInfo(@NonNull android.media.DataSourceDesc); - method public android.media.MediaDrm.KeyRequest getDrmKeyRequest(@NonNull android.media.DataSourceDesc, @Nullable byte[], @Nullable byte[], @Nullable String, int, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException; - method public String getDrmPropertyString(@NonNull android.media.DataSourceDesc, @NonNull String) throws android.media.MediaPlayer2.NoDrmSchemeException; - method @NonNull public Object prepareDrm(@NonNull android.media.DataSourceDesc, @NonNull java.util.UUID); - method public byte[] provideDrmKeyResponse(@NonNull android.media.DataSourceDesc, @Nullable byte[], @NonNull byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer2.NoDrmSchemeException; - method public void releaseDrm(@NonNull android.media.DataSourceDesc) throws android.media.MediaPlayer2.NoDrmSchemeException; - method public void restoreDrmKeys(@NonNull android.media.DataSourceDesc, @NonNull byte[]) throws android.media.MediaPlayer2.NoDrmSchemeException; - method public void setDrmPropertyString(@NonNull android.media.DataSourceDesc, @NonNull String, @NonNull String) throws android.media.MediaPlayer2.NoDrmSchemeException; - } - public final class PlaybackParams implements android.os.Parcelable { method public int getAudioStretchMode(); method public android.media.PlaybackParams setAudioStretchMode(int); } - public class UriDataSourceDesc extends android.media.DataSourceDesc { - method @Nullable public java.util.List<java.net.HttpCookie> getCookies(); - method @Nullable public java.util.Map<java.lang.String,java.lang.String> getHeaders(); - method @NonNull public android.net.Uri getUri(); - } - public static final class VolumeShaper.Configuration.Builder { method @NonNull public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int); } @@ -1202,6 +1199,91 @@ package android.media.audiofx { } +package android.media.audiopolicy { + + public class AudioMix { + method public int getMixState(); + field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff + field public static final int MIX_STATE_IDLE = 0; // 0x0 + field public static final int MIX_STATE_MIXING = 1; // 0x1 + field public static final int ROUTE_FLAG_LOOP_BACK = 2; // 0x2 + field public static final int ROUTE_FLAG_RENDER = 1; // 0x1 + } + + public static class AudioMix.Builder { + ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException; + } + + public class AudioMixingRule { + field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2 + field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1 + field public static final int RULE_MATCH_UID = 4; // 0x4 + } + + public static class AudioMixingRule.Builder { + ctor public AudioMixingRule.Builder(); + method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, Object) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.audiopolicy.AudioMixingRule.Builder allowPrivilegedPlaybackCapture(boolean); + method public android.media.audiopolicy.AudioMixingRule build(); + method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, Object) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException; + } + + public class AudioPolicy { + method public int attachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>); + method public android.media.AudioRecord createAudioRecordSink(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; + method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>); + method public int getFocusDuckingBehavior(); + method public int getStatus(); + method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; + method public void setRegistration(String); + method public String toLogFriendlyString(); + field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0 + field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0 + field public static final int FOCUS_POLICY_DUCKING_IN_POLICY = 1; // 0x1 + field public static final int POLICY_STATUS_REGISTERED = 2; // 0x2 + field public static final int POLICY_STATUS_UNREGISTERED = 1; // 0x1 + } + + public abstract static class AudioPolicy.AudioPolicyFocusListener { + ctor public AudioPolicy.AudioPolicyFocusListener(); + method public void onAudioFocusAbandon(android.media.AudioFocusInfo); + method public void onAudioFocusGrant(android.media.AudioFocusInfo, int); + method public void onAudioFocusLoss(android.media.AudioFocusInfo, boolean); + method public void onAudioFocusRequest(android.media.AudioFocusInfo, int); + } + + public abstract static class AudioPolicy.AudioPolicyStatusListener { + ctor public AudioPolicy.AudioPolicyStatusListener(); + method public void onMixStateUpdate(android.media.audiopolicy.AudioMix); + method public void onStatusChange(); + } + + public abstract static class AudioPolicy.AudioPolicyVolumeCallback { + ctor public AudioPolicy.AudioPolicyVolumeCallback(); + method public void onVolumeAdjustment(int); + } + + public static class AudioPolicy.Builder { + ctor public AudioPolicy.Builder(android.content.Context); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.audiopolicy.AudioPolicy build(); + method public void setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener); + method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException; + } + +} + package android.metrics { public class LogMaker { @@ -1377,9 +1459,6 @@ package android.net { method public static long getLoopbackRxPackets(); method public static long getLoopbackTxBytes(); method public static long getLoopbackTxPackets(); - field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40 - field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46 - field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42 } } @@ -2130,7 +2209,6 @@ package android.provider { public final class DeviceConfig { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(@NonNull String, @NonNull String, boolean); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(@NonNull String, @NonNull String, float); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(@NonNull String, @NonNull String, int); @@ -2138,7 +2216,6 @@ package android.provider { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(@NonNull String, @NonNull String); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(@NonNull String, @NonNull String, @Nullable String); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_AUTOFILL = "autofill"; @@ -2152,10 +2229,6 @@ package android.provider { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } - public static interface DeviceConfig.OnPropertyChangedListener { - method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); - } - public static class DeviceConfig.Properties { method public boolean getBoolean(@NonNull String, boolean); method public float getFloat(@NonNull String, float); @@ -2469,9 +2542,9 @@ package android.service.contentcapture { method public void onConnected(); method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent); method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId); + method public void onDataRemovalRequest(@NonNull android.view.contentcapture.DataRemovalRequest); method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDisconnected(); - method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureConditions(@NonNull String, @Nullable java.util.Set<android.view.contentcapture.ContentCaptureCondition>); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; diff --git a/api/test-removed.txt b/api/test-removed.txt index d802177e249b..83a5708a2eb3 100644 --- a/api/test-removed.txt +++ b/api/test-removed.txt @@ -1 +1,14 @@ // Signature format: 2.0 +package android.provider { + + public final class DeviceConfig { + method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + } + + public static interface DeviceConfig.OnPropertyChangedListener { + method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); + } + +} + diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp index 47617e045c12..bb8d92737563 100644 --- a/cmds/idmap2/idmap2/Create.cpp +++ b/cmds/idmap2/idmap2/Create.cpp @@ -16,6 +16,7 @@ #include <sys/stat.h> // umask #include <sys/types.h> // umask + #include <fstream> #include <memory> #include <ostream> diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp index 677c6fa155dd..b7ae9d090cee 100644 --- a/cmds/idmap2/idmap2/Lookup.cpp +++ b/cmds/idmap2/idmap2/Lookup.cpp @@ -31,15 +31,14 @@ #include "androidfw/ResourceUtils.h" #include "androidfw/StringPiece.h" #include "androidfw/Util.h" -#include "utils/String16.h" -#include "utils/String8.h" - #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" +#include "utils/String16.h" +#include "utils/String8.h" using android::ApkAssets; using android::ApkAssetsCookie; diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp index d8867fe8f497..87949085cf1d 100644 --- a/cmds/idmap2/idmap2/Main.cpp +++ b/cmds/idmap2/idmap2/Main.cpp @@ -23,12 +23,11 @@ #include <string> #include <vector> +#include "Commands.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" -#include "Commands.h" - using android::idmap2::CommandLineOptions; using android::idmap2::Result; using android::idmap2::Unit; diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index 55b1003c38af..fa9a77aa69c6 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -15,6 +15,7 @@ */ #include <dirent.h> + #include <fstream> #include <memory> #include <ostream> @@ -24,8 +25,8 @@ #include <utility> #include <vector> +#include "Commands.h" #include "android-base/properties.h" - #include "idmap2/CommandLineOptions.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" @@ -35,8 +36,6 @@ #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" -#include "Commands.h" - using android::idmap2::CommandLineOptions; using android::idmap2::Error; using android::idmap2::Idmap; @@ -211,7 +210,9 @@ Result<Unit> Scan(const std::vector<std::string>& args) { const auto create_ok = Create(create_args); if (!create_ok) { - return Error(create_ok.GetError(), "failed to create idmap"); + LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path + << "\": " << create_ok.GetError().GetMessage(); + continue; } } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index 4f653796ce3f..8ee79f61520a 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2d/Idmap2Service.h" + #include <sys/stat.h> // umask #include <sys/types.h> // umask #include <unistd.h> @@ -28,15 +30,12 @@ #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "binder/IPCThreadState.h" -#include "utils/String8.h" - #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" #include "idmap2/Policies.h" #include "idmap2/SysTrace.h" - -#include "idmap2d/Idmap2Service.h" +#include "utils/String8.h" using android::IPCThreadState; using android::binder::Status; diff --git a/cmds/idmap2/idmap2d/Main.cpp b/cmds/idmap2/idmap2d/Main.cpp index 4393dcc130ec..2707049fa677 100644 --- a/cmds/idmap2/idmap2d/Main.cpp +++ b/cmds/idmap2/idmap2d/Main.cpp @@ -21,13 +21,11 @@ #include <binder/ProcessState.h> #include <cstdlib> // EXIT_{FAILURE,SUCCESS} - #include <iostream> #include <sstream> -#include "android-base/macros.h" - #include "Idmap2Service.h" +#include "android-base/macros.h" using android::BinderService; using android::IPCThreadState; diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index 5cc0664b2bed..ebbb5ffc989d 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -52,11 +52,9 @@ #include <vector> #include "android-base/macros.h" - #include "androidfw/ApkAssets.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" - #include "idmap2/Policies.h" namespace android::idmap2 { diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h index cd76b84ccc0a..90c698cc6e49 100644 --- a/cmds/idmap2/include/idmap2/Policies.h +++ b/cmds/idmap2/include/idmap2/Policies.h @@ -17,11 +17,10 @@ #include <string> #include <vector> +#include "Result.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" -#include "Result.h" - #ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ #define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h index c388f4b94251..5111bb2eaab2 100644 --- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h +++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h @@ -21,7 +21,6 @@ #include <memory> #include "androidfw/AssetManager2.h" - #include "idmap2/Idmap.h" namespace android { diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h index 7e33b3b06fc3..2e543d4fabdd 100644 --- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h +++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h @@ -22,7 +22,6 @@ #include <string> #include "androidfw/AssetManager2.h" - #include "idmap2/Idmap.h" namespace android { diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h index 1d81c486d504..8797a788dd1d 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -21,7 +21,6 @@ #include <string> #include "androidfw/AssetManager2.h" - #include "idmap2/Idmap.h" #include "idmap2/Result.h" #include "idmap2/ZipFile.h" diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp index 96513283ac51..dee2d219cbe1 100644 --- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp +++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ +#include "idmap2/BinaryStreamVisitor.h" + #include <algorithm> #include <cstring> #include <string> #include "android-base/macros.h" -#include "idmap2/BinaryStreamVisitor.h" - namespace android::idmap2 { void BinaryStreamVisitor::Write16(uint16_t value) { diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp index d5fd2ce38b11..5b0ae92df887 100644 --- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp +++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2/CommandLineOptions.h" + #include <algorithm> #include <iomanip> #include <iostream> @@ -24,8 +26,6 @@ #include <vector> #include "android-base/macros.h" - -#include "idmap2/CommandLineOptions.h" #include "idmap2/Result.h" namespace android::idmap2 { diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp index a9b68cd6d5d5..3e8e32989a09 100644 --- a/cmds/idmap2/libidmap2/FileUtils.cpp +++ b/cmds/idmap2/libidmap2/FileUtils.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2/FileUtils.h" + #include <dirent.h> #include <sys/types.h> #include <unistd.h> @@ -33,8 +35,6 @@ #include "android-base/stringprintf.h" #include "private/android_filesystem_config.h" -#include "idmap2/FileUtils.h" - namespace android::idmap2::utils { std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse, diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 49470b4f4e95..aec1a6fc2bae 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2/Idmap.h" + #include <algorithm> #include <iostream> #include <iterator> @@ -28,14 +30,12 @@ #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "androidfw/AssetManager2.h" -#include "utils/String16.h" -#include "utils/String8.h" - -#include "idmap2/Idmap.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "idmap2/ZipFile.h" +#include "utils/String16.h" +#include "utils/String8.h" namespace android::idmap2 { diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp index 7c4555633fd2..0a0cecf13932 100644 --- a/cmds/idmap2/libidmap2/Policies.cpp +++ b/cmds/idmap2/libidmap2/Policies.cpp @@ -14,15 +14,15 @@ * limitations under the License. */ +#include "idmap2/Policies.h" + #include <iterator> #include <map> #include <string> #include <vector> #include "androidfw/ResourceTypes.h" - #include "idmap2/Idmap.h" -#include "idmap2/Policies.h" #include "idmap2/Result.h" namespace android::idmap2 { diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp index fc9677994fc0..fbf2c777be9a 100644 --- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ +#include "idmap2/PrettyPrintVisitor.h" + #include <string> #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "androidfw/ApkAssets.h" - -#include "idmap2/PrettyPrintVisitor.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp index 1149c905a178..dd14fd47aea8 100644 --- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ +#include "idmap2/RawPrintVisitor.h" + #include <cstdarg> #include <string> #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "androidfw/ApkAssets.h" - -#include "idmap2/RawPrintVisitor.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp index a24836da7f3a..71ba3f0f1ac2 100644 --- a/cmds/idmap2/libidmap2/ResourceUtils.cpp +++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ +#include "idmap2/ResourceUtils.h" + #include <memory> #include <string> #include "androidfw/StringPiece.h" #include "androidfw/Util.h" - -#include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" diff --git a/cmds/idmap2/libidmap2/Result.cpp b/cmds/idmap2/libidmap2/Result.cpp index 471dab2e0411..1eac25f1b955 100644 --- a/cmds/idmap2/libidmap2/Result.cpp +++ b/cmds/idmap2/libidmap2/Result.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ +#include "idmap2/Result.h" + #include <cstdarg> #include "android-base/stringprintf.h" -#include "idmap2/Result.h" - namespace android::idmap2 { // NOLINTNEXTLINE(cert-dcl50-cpp) diff --git a/cmds/idmap2/libidmap2/Xml.cpp b/cmds/idmap2/libidmap2/Xml.cpp index 0075a922d676..264586829c47 100644 --- a/cmds/idmap2/libidmap2/Xml.cpp +++ b/cmds/idmap2/libidmap2/Xml.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ +#include "idmap2/Xml.h" + #include <map> #include <memory> #include <string> #include <utility> -#include "idmap2/Xml.h" - namespace android::idmap2 { std::unique_ptr<const Xml> Xml::Create(const uint8_t* data, size_t size, bool copyData) { diff --git a/cmds/idmap2/libidmap2/ZipFile.cpp b/cmds/idmap2/libidmap2/ZipFile.cpp index 0f0732466256..812fd6eacbf9 100644 --- a/cmds/idmap2/libidmap2/ZipFile.cpp +++ b/cmds/idmap2/libidmap2/ZipFile.cpp @@ -14,11 +14,12 @@ * limitations under the License. */ +#include "idmap2/ZipFile.h" + #include <memory> #include <string> #include "idmap2/Result.h" -#include "idmap2/ZipFile.h" namespace android::idmap2 { diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp index 9a5b6331cb20..9cdc86ca181a 100644 --- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp +++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp @@ -19,17 +19,14 @@ #include <string> #include <utility> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "androidfw/ApkAssets.h" #include "androidfw/Idmap.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/Idmap.h" -#include "TestHelpers.h" - using ::testing::NotNull; namespace android::idmap2 { diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp index d567af64b16a..6e83fc9abdb1 100644 --- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp +++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp @@ -25,19 +25,16 @@ #include <string> #include <vector> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "android-base/file.h" #include "androidfw/ApkAssets.h" #include "androidfw/Idmap.h" #include "androidfw/LoadedArsc.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" -#include "TestHelpers.h" - namespace android::idmap2 { TEST(CommandLineOptionsTests, Flag) { diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp index 34a0097b0316..f4a306e41e32 100644 --- a/cmds/idmap2/tests/FileUtilsTests.cpp +++ b/cmds/idmap2/tests/FileUtilsTests.cpp @@ -15,19 +15,17 @@ */ #include <dirent.h> + #include <set> #include <string> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "android-base/macros.h" #include "android-base/stringprintf.h" -#include "private/android_filesystem_config.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/FileUtils.h" - -#include "TestHelpers.h" +#include "private/android_filesystem_config.h" using ::testing::NotNull; diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp index 91bc4ddb397f..c18744ccb2d5 100644 --- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp +++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp @@ -34,16 +34,13 @@ #include <string> #include <vector> +#include "TestHelpers.h" +#include "androidfw/PosixUtils.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "androidfw/PosixUtils.h" -#include "private/android_filesystem_config.h" - #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" - -#include "TestHelpers.h" +#include "private/android_filesystem_config.h" using ::android::util::ExecuteBinary; using ::testing::NotNull; @@ -264,6 +261,24 @@ TEST_F(Idmap2BinaryTests, Scan) { ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; ASSERT_EQ(result->stdout, ""); + + // the signature idmap failing to generate should not cause scanning to fail + // clang-format off + result = ExecuteBinary({"idmap2", + "scan", + "--input-directory", GetTestDataPath(), + "--recursive", + "--target-package-name", "test.target", + "--target-apk-path", GetTargetApkPath(), + "--output-directory", GetTempDirPath(), + "--override-policy", "public"}); + // clang-format on + ASSERT_THAT(result, NotNull()); + ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; + ASSERT_EQ(result->stdout, expected.str()); + unlink(idmap_static_no_name_path.c_str()); + unlink(idmap_static_2_path.c_str()); + unlink(idmap_static_1_path.c_str()); } TEST_F(Idmap2BinaryTests, Lookup) { diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 621f50337aa3..90fe9a79bd1f 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -15,7 +15,6 @@ */ #include <cstdio> // fclose - #include <fstream> #include <memory> #include <sstream> @@ -23,18 +22,15 @@ #include <utility> #include <vector> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "android-base/macros.h" #include "androidfw/ApkAssets.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" -#include "TestHelpers.h" - using ::testing::IsNull; using ::testing::NotNull; diff --git a/cmds/idmap2/tests/Main.cpp b/cmds/idmap2/tests/Main.cpp index 2b13fed8d60d..3e753e974465 100644 --- a/cmds/idmap2/tests/Main.cpp +++ b/cmds/idmap2/tests/Main.cpp @@ -16,12 +16,10 @@ #include <string> +#include "TestHelpers.h" #include "android-base/file.h" - #include "gtest/gtest.h" -#include "TestHelpers.h" - namespace android::idmap2 { std::string GetTestDataPath() { diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp index a76da533cdcb..e30da76ddd98 100644 --- a/cmds/idmap2/tests/PoliciesTests.cpp +++ b/cmds/idmap2/tests/PoliciesTests.cpp @@ -16,9 +16,8 @@ #include <string> -#include "gtest/gtest.h" - #include "TestHelpers.h" +#include "gtest/gtest.h" #include "idmap2/Policies.h" using android::idmap2::PolicyBitmask; diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp index 27a3880f67b6..c41250457678 100644 --- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp @@ -18,18 +18,15 @@ #include <sstream> #include <string> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "androidfw/ApkAssets.h" #include "androidfw/Idmap.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/Idmap.h" #include "idmap2/Policies.h" #include "idmap2/PrettyPrintVisitor.h" -#include "TestHelpers.h" - using ::testing::NotNull; using android::ApkAssets; diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index 7372148f0f0e..64518fdf8dee 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -19,14 +19,12 @@ #include <sstream> #include <string> +#include "TestHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - #include "idmap2/Idmap.h" #include "idmap2/RawPrintVisitor.h" -#include "TestHelpers.h" - using ::testing::NotNull; namespace android::idmap2 { diff --git a/cmds/idmap2/tests/ResourceUtilsTests.cpp b/cmds/idmap2/tests/ResourceUtilsTests.cpp index ad78685646b4..9ed807ccd8f9 100644 --- a/cmds/idmap2/tests/ResourceUtilsTests.cpp +++ b/cmds/idmap2/tests/ResourceUtilsTests.cpp @@ -17,15 +17,13 @@ #include <memory> #include <string> +#include "TestHelpers.h" +#include "androidfw/ApkAssets.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "androidfw/ApkAssets.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" -#include "TestHelpers.h" - using ::testing::NotNull; namespace android::idmap2 { diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp index 5f4daed521c0..cbced0ae32fb 100644 --- a/cmds/idmap2/tests/ResultTests.cpp +++ b/cmds/idmap2/tests/ResultTests.cpp @@ -20,7 +20,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" - #include "idmap2/Result.h" namespace android::idmap2 { diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h index 45525a5b7657..adea3293534d 100644 --- a/cmds/idmap2/tests/TestHelpers.h +++ b/cmds/idmap2/tests/TestHelpers.h @@ -19,6 +19,9 @@ #include <string> +#include "gmock/gmock.h" +#include "gtest/gtest.h" + namespace android::idmap2 { const unsigned char idmap_raw_data[] = { diff --git a/cmds/idmap2/tests/XmlTests.cpp b/cmds/idmap2/tests/XmlTests.cpp index fe79d8f2c5a9..df63211a9209 100644 --- a/cmds/idmap2/tests/XmlTests.cpp +++ b/cmds/idmap2/tests/XmlTests.cpp @@ -16,13 +16,11 @@ #include <cstdio> // fclose -#include "idmap2/Xml.h" -#include "idmap2/ZipFile.h" - +#include "TestHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "TestHelpers.h" +#include "idmap2/Xml.h" +#include "idmap2/ZipFile.h" using ::testing::IsNull; using ::testing::NotNull; diff --git a/cmds/idmap2/tests/ZipFileTests.cpp b/cmds/idmap2/tests/ZipFileTests.cpp index 79be43ce0e42..3fca43621945 100644 --- a/cmds/idmap2/tests/ZipFileTests.cpp +++ b/cmds/idmap2/tests/ZipFileTests.cpp @@ -17,13 +17,11 @@ #include <cstdio> // fclose #include <string> -#include "idmap2/Result.h" -#include "idmap2/ZipFile.h" - +#include "TestHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "TestHelpers.h" +#include "idmap2/Result.h" +#include "idmap2/ZipFile.h" using ::testing::IsNull; using ::testing::NotNull; diff --git a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml index 9e6a4536cb51..5df0bea555b1 100644 --- a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml +++ b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml @@ -19,5 +19,7 @@ <application android:hasCode="false"/> <overlay android:targetPackage="test.target" - android:targetName="TestResources"/> + android:targetName="TestResources" + android:isStatic="true" + android:priority="10"/> </manifest> diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk Binary files differindex b2c490dcbb90..51e19de082ed 100644 --- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk +++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 048e8fcbe37b..5778fa9f6903 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -279,7 +279,7 @@ message Atom { } // Pulled events will start at field 10000. - // Next: 10058 + // Next: 10059 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; @@ -339,6 +339,8 @@ message Atom { GpuStatsAppInfo gpu_stats_app_info = 10055; SystemIonHeapSize system_ion_heap_size = 10056; AppsOnExternalStorageInfo apps_on_external_storage_info = 10057; + FaceSettings face_settings = 10058; + CoolingDevice cooling_device = 10059; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -409,17 +411,25 @@ message KeyValuePairsAtom { * frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java */ message ThermalThrottlingStateChanged { + // The type of temperature being reported (CPU, GPU, SKIN, etc) optional android.os.TemperatureTypeEnum sensor_type = 1; + // Throttling state, this field is DEPRECATED enum State { UNKNOWN = 0; - START = 1; - STOP = 2; + START = 1; // START indicated that throttling was triggered. + STOP = 2; // STOP indicates that throttling was cleared. } - optional State state = 2; + // Temperature in deci degrees celsius optional float temperature = 3; + + // Severity of throttling + optional android.os.ThrottlingSeverityEnum severity = 4; + + // Thermistor name + optional string sensor_name = 5; } /** @@ -3956,8 +3966,7 @@ message BatteryLevel { * Pulls the temperature of various parts of the device. * The units are tenths of a degree Celsius. Eg: 30.3C is reported as 303. * - * Pulled from: - * frameworks/base/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp + * Pulled from StatsCompanionService.java */ message Temperature { // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY, BCL_. @@ -3969,6 +3978,9 @@ message Temperature { // Temperature in tenths of a degree C. // For BCL, it is decimillivolt, decimilliamps, and percentage * 10. optional int32 temperature_deci_celsius = 3; + + // Relative severity of the throttling, see enum definition. + optional android.os.ThrottlingSeverityEnum severity = 4; } /** @@ -5584,6 +5596,7 @@ message BubbleUIChanged { SWIPE_LEFT = 13; SWIPE_RIGHT = 14; STACK_EXPANDED = 15; + FLYOUT = 16; } optional Action action = 6; @@ -5925,3 +5938,39 @@ message AppsOnExternalStorageInfo { // The name of the package that is installed on the external storage. optional string package_name = 2; } + +/** + * Logs the settings related to Face. + * Logged from: + * frameworks/base/services/core/java/com/android/server/stats + */ +message FaceSettings { + // Whether or not face unlock is allowed on Keyguard. + optional bool unlock_keyguard_enabled = 1; + // Whether or not face unlock dismisses the Keyguard. + optional bool unlock_dismisses_keyguard = 2; + // Whether or not face unlock requires attention. + optional bool unlock_attention_required = 3; + // Whether or not face unlock is allowed for apps (through BiometricPrompt). + optional bool unlock_app_enabled = 4; + // Whether or not face unlock always requires user confirmation. + optional bool unlock_always_require_confirmation = 5; + // Whether or not a diverse set of poses are required during enrollment. + optional bool unlock_diversity_required = 6; +} + +/** + * Logs cooling devices maintained by the kernel. + * + * Pulled from StatsCompanionService.java + */ +message CoolingDevice { + // The type of cooling device being reported. Eg. CPU, GPU... + optional android.os.CoolingTypeEnum device_location = 1; + // The name of the cooling device source. Eg. CPU0 + optional string device_name = 2; + // Current throttle state of the cooling device. The value can any unsigned + // integer between 0 and max_state defined in its driver. 0 means device is + // not in throttling, higher value means deeper throttling. + optional int32 state = 3; +} diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index d6411a748081..ca73059d8b8e 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -159,6 +159,9 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // temperature {android::util::TEMPERATURE, {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}}, + // cooling_device + {android::util::COOLING_DEVICE, + {.puller = new StatsCompanionServicePuller(android::util::COOLING_DEVICE)}}, // binder_calls {android::util::BINDER_CALLS, {.additiveFields = {4, 5, 6, 8, 12}, @@ -254,6 +257,9 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // AppsOnExternalStorageInfo {android::util::APPS_ON_EXTERNAL_STORAGE_INFO, {.puller = new StatsCompanionServicePuller(android::util::APPS_ON_EXTERNAL_STORAGE_INFO)}}, + // Face Settings + {android::util::FACE_SETTINGS, + {.puller = new StatsCompanionServicePuller(android::util::FACE_SETTINGS)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b6e5754aa65f..5e5611bcf058 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -16,6 +16,7 @@ package android.app; +import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE; import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY; import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE; @@ -27,6 +28,8 @@ import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS; import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX; import static android.view.Display.INVALID_DISPLAY; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; @@ -193,6 +196,7 @@ import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; final class RemoteServiceException extends AndroidRuntimeException { public RemoteServiceException(String msg) { @@ -224,6 +228,17 @@ public final class ActivityThread extends ClientTransactionHandler { private static final boolean DEBUG_PROVIDER = false; public static final boolean DEBUG_ORDER = false; private static final long MIN_TIME_BETWEEN_GCS = 5*1000; + /** + * If the activity doesn't become idle in time, the timeout will ensure to apply the pending top + * process state. + */ + private static final long PENDING_TOP_PROCESS_STATE_TIMEOUT = 1000; + /** + * The delay to release the provider when it has no more references. It reduces the number of + * transactions for acquiring and releasing provider if the client accesses the provider + * frequently in a short time. + */ + private static final long CONTENT_PROVIDER_RETAIN_TIME = 1000; private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003; /** Type for IActivityManager.serviceDoneExecuting: anonymous operation */ @@ -236,6 +251,11 @@ public final class ActivityThread extends ClientTransactionHandler { // Whether to invoke an activity callback after delivering new configuration. private static final boolean REPORT_TO_ACTIVITY = true; + /** Use foreground GC policy (less pause time) and higher JIT weight. */ + private static final int VM_PROCESS_STATE_JANK_PERCEPTIBLE = 0; + /** Use background GC policy and default JIT threshold. */ + private static final int VM_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1; + /** * Denotes an invalid sequence number corresponding to a process state change. */ @@ -290,6 +310,11 @@ public final class ActivityThread extends ClientTransactionHandler { // Number of activities that are currently visible on-screen. @UnsupportedAppUsage int mNumVisibleActivities = 0; + private final AtomicInteger mNumLaunchingActivities = new AtomicInteger(); + @GuardedBy("mAppThread") + private int mLastProcessState = PROCESS_STATE_UNKNOWN; + @GuardedBy("mAppThread") + private int mPendingProcessState = PROCESS_STATE_UNKNOWN; ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>(); private int mLastSessionId; @UnsupportedAppUsage @@ -867,17 +892,6 @@ public final class ActivityThread extends ClientTransactionHandler { private class ApplicationThread extends IApplicationThread.Stub { private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s"; - private int mLastProcessState = -1; - - private void updatePendingConfiguration(Configuration config) { - synchronized (mResourcesManager) { - if (mPendingConfiguration == null || - mPendingConfiguration.isOtherSeqNewer(config)) { - mPendingConfiguration = config; - } - } - } - public final void scheduleSleeping(IBinder token, boolean sleeping) { sendMessage(H.SLEEPING, token, sleeping ? 1 : 0); } @@ -1554,27 +1568,6 @@ public final class ActivityThread extends ClientTransactionHandler { updateProcessState(state, true); } - public void updateProcessState(int processState, boolean fromIpc) { - synchronized (this) { - if (mLastProcessState != processState) { - mLastProcessState = processState; - // Update Dalvik state based on ActivityManager.PROCESS_STATE_* constants. - final int DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE = 0; - final int DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1; - int dalvikProcessState = DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE; - // TODO: Tune this since things like gmail sync are important background but not jank perceptible. - if (processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { - dalvikProcessState = DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE; - } - VMRuntime.getRuntime().updateProcessState(dalvikProcessState); - if (false) { - Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState - + (fromIpc ? " (from ipc": "")); - } - } - } - } - /** * Updates {@link #mNetworkBlockSeq}. This is used by ActivityManagerService to inform * the main thread that it needs to wait for the network rules to get updated before @@ -1655,16 +1648,6 @@ public final class ActivityThread extends ClientTransactionHandler { } } - @Override - public void updatePendingConfiguration(Configuration config) { - mAppThread.updatePendingConfiguration(config); - } - - @Override - public void updateProcessState(int processState, boolean fromIpc) { - mAppThread.updateProcessState(processState, fromIpc); - } - class H extends Handler { public static final int BIND_APPLICATION = 110; @UnsupportedAppUsage @@ -1989,6 +1972,7 @@ public final class ActivityThread extends ClientTransactionHandler { if (stopProfiling) { mProfiler.stopProfiling(); } + applyPendingProcessState(); return false; } } @@ -2933,6 +2917,68 @@ public final class ActivityThread extends ClientTransactionHandler { return mActivities.get(token); } + @Override + public void updatePendingConfiguration(Configuration config) { + synchronized (mResourcesManager) { + if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(config)) { + mPendingConfiguration = config; + } + } + } + + @Override + public void updateProcessState(int processState, boolean fromIpc) { + synchronized (mAppThread) { + if (mLastProcessState == processState) { + return; + } + mLastProcessState = processState; + // Defer the top state for VM to avoid aggressive JIT compilation affecting activity + // launch time. + if (processState == ActivityManager.PROCESS_STATE_TOP + && mNumLaunchingActivities.get() > 0) { + mPendingProcessState = processState; + mH.postDelayed(this::applyPendingProcessState, PENDING_TOP_PROCESS_STATE_TIMEOUT); + } else { + mPendingProcessState = PROCESS_STATE_UNKNOWN; + updateVmProcessState(processState); + } + if (localLOGV) { + Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState + + (fromIpc ? " (from ipc" : "")); + } + } + } + + /** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */ + private void updateVmProcessState(int processState) { + // TODO: Tune this since things like gmail sync are important background but not jank + // perceptible. + final int state = processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + ? VM_PROCESS_STATE_JANK_PERCEPTIBLE + : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE; + VMRuntime.getRuntime().updateProcessState(state); + } + + private void applyPendingProcessState() { + synchronized (mAppThread) { + if (mPendingProcessState == PROCESS_STATE_UNKNOWN) { + return; + } + final int pendingState = mPendingProcessState; + mPendingProcessState = PROCESS_STATE_UNKNOWN; + // Only apply the pending state if the last state doesn't change. + if (pendingState == mLastProcessState) { + updateVmProcessState(pendingState); + } + } + } + + @Override + public void countLaunchingActivities(int num) { + mNumLaunchingActivities.getAndAdd(num); + } + @UnsupportedAppUsage public final void sendActivityResult( IBinder token, String id, int requestCode, @@ -4503,7 +4549,7 @@ public final class ActivityThread extends ClientTransactionHandler { if (!show && !r.stopped) { performStopActivityInner(r, null /* stopInfo */, show, false /* saveState */, false /* finalStateRequest */, "handleWindowVisibility"); - } else if (show && r.stopped) { + } else if (show && r.getLifecycleState() == ON_STOP) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -4564,7 +4610,7 @@ public final class ActivityThread extends ClientTransactionHandler { private void onCoreSettingsChange() { if (updateDebugViewAttributeState()) { // request all activities to relaunch for the changes to take place - relaunchAllActivities(); + relaunchAllActivities(false /* preserveWindows */); } } @@ -4581,10 +4627,13 @@ public final class ActivityThread extends ClientTransactionHandler { return previousState != View.sDebugViewAttributes; } - private void relaunchAllActivities() { + private void relaunchAllActivities(boolean preserveWindows) { for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) { - final Activity activity = entry.getValue().activity; - if (!activity.mFinished) { + final ActivityClientRecord r = entry.getValue(); + if (!r.activity.mFinished) { + if (preserveWindows && r.window != null) { + r.mPreserveWindow = true; + } scheduleRelaunchActivity(entry.getKey()); } } @@ -5417,7 +5466,8 @@ public final class ActivityThread extends ClientTransactionHandler { } } - void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) { + @VisibleForTesting(visibility = PACKAGE) + public void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) { // Updates triggered by package installation go through a package update // receiver. Here we try to capture ApplicationInfo changes that are // caused by other sources, such as overlays. That means we want to be as conservative @@ -5463,7 +5513,8 @@ public final class ActivityThread extends ClientTransactionHandler { newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1; handleConfigurationChanged(newConfig, null); - relaunchAllActivities(); + // Preserve windows to avoid black flickers when overlays change. + relaunchAllActivities(true /* preserveWindows */); } static void freeTextLayoutCachesIfNeeded(int configDiff) { @@ -6498,16 +6549,13 @@ public final class ActivityThread extends ClientTransactionHandler { if (!prc.removePending) { // Schedule the actual remove asynchronously, since we don't know the context // this will be called in. - // TODO: it would be nice to post a delayed message, so - // if we come back and need the same provider quickly - // we will still have it available. if (DEBUG_PROVIDER) { Slog.v(TAG, "releaseProvider: Enqueueing pending removal - " + prc.holder.info.name); } prc.removePending = true; Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, prc); - mH.sendMessage(msg); + mH.sendMessageDelayed(msg, CONTENT_PROVIDER_RETAIN_TIME); } else { Slog.w(TAG, "Duplicate remove pending of provider " + prc.holder.info.name); } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 15982a796a7e..6f9224481eba 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -38,7 +38,6 @@ import android.os.Parcelable; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.UserManager; import android.util.ArrayMap; import android.util.LongSparseArray; @@ -5209,7 +5208,6 @@ public class AppOpsManager { * @hide */ public int noteProxyOpNoThrow(int op, String proxiedPackageName, int proxiedUid) { - logOperationIfNeeded(op, mContext.getOpPackageName(), proxiedPackageName); try { return mService.noteProxyOperation(op, Process.myUid(), mContext.getOpPackageName(), proxiedUid, proxiedPackageName); @@ -5238,7 +5236,6 @@ public class AppOpsManager { */ @UnsupportedAppUsage public int noteOpNoThrow(int op, int uid, String packageName) { - logOperationIfNeeded(op, packageName, null); try { return mService.noteOperation(op, uid, packageName); } catch (RemoteException e) { @@ -5346,7 +5343,6 @@ public class AppOpsManager { * @hide */ public int startOpNoThrow(int op, int uid, String packageName, boolean startIfModeDefault) { - logOperationIfNeeded(op, packageName, null); try { return mService.startOperation(getToken(mService), op, uid, packageName, startIfModeDefault); @@ -5363,7 +5359,6 @@ public class AppOpsManager { * @hide */ public void finishOp(int op, int uid, String packageName) { - logOperationIfNeeded(op, packageName, null); try { mService.finishOperation(getToken(mService), op, uid, packageName); } catch (RemoteException e) { @@ -5703,45 +5698,4 @@ public class AppOpsManager { return AppOpsManager.MODE_DEFAULT; } - - private static void logOperationIfNeeded(int op, String callingPackage, String proxiedPackage) { - // Check if debug logging propety is enabled. - if (!SystemProperties.getBoolean(DEBUG_LOGGING_ENABLE_PROP, false)) { - return; - } - // Check if this package should be logged. - String packages = SystemProperties.get(DEBUG_LOGGING_PACKAGES_PROP, ""); - if (!"".equals(packages) && callingPackage != null) { - boolean found = false; - for (String pkg : packages.split(",")) { - if (callingPackage.equals(pkg)) { - found = true; - break; - } - } - if (!found) { - return; - } - } - String opStr = opToName(op); - // Check if this app op should be logged - String logOps = SystemProperties.get(DEBUG_LOGGING_OPS_PROP, ""); - if (!"".equals(logOps)) { - boolean found = false; - for (String logOp : logOps.split(",")) { - if (opStr.equals(logOp)) { - found = true; - break; - } - } - if (!found) { - return; - } - } - - // Log a stack trace - Exception here = new Exception("HERE!"); - android.util.Log.i(DEBUG_LOGGING_TAG, "Note operation package= " + callingPackage - + " proxied= " + proxiedPackage + " op= " + opStr, here); - } } diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 9dc8b45a71dc..d308adc52e15 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -78,6 +78,8 @@ public abstract class ClientTransactionHandler { /** Set current process state. */ public abstract void updateProcessState(int processState, boolean fromIpc); + /** Count how many activities are launching. */ + public abstract void countLaunchingActivities(int num); // Execute phase related logic and handlers. Methods here execute actual lifecycle transactions // and deliver callbacks. diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 1785d2a0843b..48ca71690a1b 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -223,7 +223,7 @@ interface IActivityManager { void enterSafeMode(); void noteWakeupAlarm(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String sourcePkg, in String tag); - void removeContentProvider(in IBinder connection, boolean stable); + oneway void removeContentProvider(in IBinder connection, boolean stable); @UnsupportedAppUsage void setRequestedOrientation(in IBinder token, int requestedOrientation); void unbindFinished(in IBinder token, in Intent service, boolean doRebind); diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index 2e14d03a912c..e6682d620b99 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -414,7 +414,6 @@ public final class StatsManager { * Returns the experiments IDs registered with statsd, or an empty array if there aren't any. * * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service - * @hide */ @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS}) public long[] getRegisteredExperimentIds() diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING index 14c58e744dac..def1f457fb4a 100644 --- a/core/java/android/app/TEST_MAPPING +++ b/core/java/android/app/TEST_MAPPING @@ -27,5 +27,15 @@ } ] } + ], + "postsubmit": [ + { + "file_patterns": ["(/|^)ActivityThreadClientTest.java"], + "name": "FrameworksMockingCoreTests" + }, + { + "file_patterns": ["(/|^)ActivityThreadTest.java"], + "name": "FrameworksCoreTests" + } ] } diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index dd00e5a74382..de64db9def64 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -16,6 +16,8 @@ package android.app; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; @@ -58,23 +60,27 @@ public class TaskInfo { * The base intent of the task (generally the intent that launched the task). This intent can * be used to relaunch the task (if it is no longer running) or brought to the front if it is. */ + @NonNull public Intent baseIntent; /** * The component of the first activity in the task, can be considered the "application" of this * task. */ + @Nullable public ComponentName baseActivity; /** * The component of the top activity in the task, currently showing to the user. */ + @Nullable public ComponentName topActivity; /** * The component of the target activity if this task was started from an activity alias. * Otherwise, this is null. */ + @Nullable public ComponentName origActivity; /** @@ -82,6 +88,7 @@ public class TaskInfo { * alias). * @hide */ + @Nullable public ComponentName realActivity; /** @@ -106,6 +113,7 @@ public class TaskInfo { * The recent activity values for the highest activity in the stack to have set the values. * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}. */ + @Nullable public ActivityManager.TaskDescription taskDescription; /** @@ -126,6 +134,7 @@ public class TaskInfo { * The current configuration of the task. * @hide */ + @NonNull @UnsupportedAppUsage public final Configuration configuration = new Configuration(); diff --git a/core/java/android/app/Vr2dDisplayProperties.java b/core/java/android/app/Vr2dDisplayProperties.java index bcb8592183e9..fc200bf05253 100644 --- a/core/java/android/app/Vr2dDisplayProperties.java +++ b/core/java/android/app/Vr2dDisplayProperties.java @@ -17,6 +17,7 @@ package android.app; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -136,7 +137,7 @@ public final class Vr2dDisplayProperties implements Parcelable { /** * Prints out dump info. */ - public void dump(PrintWriter pw, String prefix) { + public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { pw.println(prefix + toString()); } @@ -188,7 +189,7 @@ public final class Vr2dDisplayProperties implements Parcelable { /** * Convenience class for creating Vr2dDisplayProperties. */ - public static class Builder { + public static final class Builder { private int mAddedFlags = 0; private int mRemovedFlags = 0; @@ -203,6 +204,7 @@ public final class Vr2dDisplayProperties implements Parcelable { /** * Sets the dimensions to use for the virtual display. */ + @NonNull public Builder setDimensions(int width, int height, int dpi) { mWidth = width; mHeight = height; @@ -213,6 +215,7 @@ public final class Vr2dDisplayProperties implements Parcelable { /** * Toggles the virtual display functionality for 2D activities in VR. */ + @NonNull public Builder setEnabled(boolean enabled) { if (enabled) { addFlags(FLAG_VIRTUAL_DISPLAY_ENABLED); @@ -225,6 +228,7 @@ public final class Vr2dDisplayProperties implements Parcelable { /** * Adds property flags. */ + @NonNull public Builder addFlags(@Vr2dDisplayFlag int flags) { mAddedFlags |= flags; mRemovedFlags &= ~flags; @@ -234,6 +238,7 @@ public final class Vr2dDisplayProperties implements Parcelable { /** * Removes property flags. */ + @NonNull public Builder removeFlags(@Vr2dDisplayFlag int flags) { mRemovedFlags |= flags; mAddedFlags &= ~flags; @@ -243,6 +248,7 @@ public final class Vr2dDisplayProperties implements Parcelable { /** * Builds the Vr2dDisplayProperty instance. */ + @NonNull public Vr2dDisplayProperties build() { return new Vr2dDisplayProperties(mWidth, mHeight, mDpi, mAddedFlags, mRemovedFlags); } diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java index 5f1a94c835c3..c74f8c389c20 100644 --- a/core/java/android/app/VrManager.java +++ b/core/java/android/app/VrManager.java @@ -2,6 +2,7 @@ package android.app; import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -71,7 +72,7 @@ public class VrManager { android.Manifest.permission.ACCESS_VR_STATE }) public void registerVrStateCallback(@NonNull @CallbackExecutor Executor executor, - VrStateCallback callback) { + @NonNull VrStateCallback callback) { if (callback == null || mCallbackMap.containsKey(callback)) { return; } @@ -99,7 +100,7 @@ public class VrManager { android.Manifest.permission.RESTRICTED_VR_ACCESS, android.Manifest.permission.ACCESS_VR_STATE }) - public void unregisterVrStateCallback(VrStateCallback callback) { + public void unregisterVrStateCallback(@NonNull VrStateCallback callback) { CallbackEntry entry = mCallbackMap.remove(callback); if (entry != null) { try { @@ -175,7 +176,7 @@ public class VrManager { */ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties( - Vr2dDisplayProperties vr2dDisplayProp) { + @NonNull Vr2dDisplayProperties vr2dDisplayProp) { try { mService.setVr2dDisplayProperties(vr2dDisplayProp); } catch (RemoteException e) { @@ -220,7 +221,7 @@ public class VrManager { * @param componentName not used */ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) - public void setVrInputMethod(ComponentName componentName) { + public void setVrInputMethod(@Nullable ComponentName componentName) { } /** diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java index 3f2f2090bf33..cd635d635ce1 100644 --- a/core/java/android/app/prediction/AppPredictor.java +++ b/core/java/android/app/prediction/AppPredictor.java @@ -271,7 +271,9 @@ public final class AppPredictor { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); } - destroy(); + if (!mIsClosed.get()) { + destroy(); + } } finally { super.finalize(); } diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java index ed45b2f45383..4704661c2b24 100644 --- a/core/java/android/app/prediction/AppTarget.java +++ b/core/java/android/app/prediction/AppTarget.java @@ -204,24 +204,49 @@ public final class AppTarget implements Parcelable { private int mRank; /** - * @param id A unique id for this launchable target. + * @deprecated Use the other Builder constructors. * @hide */ - @SystemApi - @TestApi + @Deprecated public Builder(@NonNull AppTargetId id) { mId = id; } /** - * Sets the target to be an app. - * - * @param packageName PackageName of the app + * @param id A unique id for this launchable target. + * @param packageName PackageName of the target. * @param user The UserHandle of the user which this target belongs to. - * - * @throws IllegalArgumentException is the target is already set + * @hide + */ + @SystemApi + @TestApi + public Builder(@NonNull AppTargetId id, @NonNull String packageName, + @NonNull UserHandle user) { + mId = Preconditions.checkNotNull(id); + mPackageName = Preconditions.checkNotNull(packageName); + mUser = Preconditions.checkNotNull(user); + } + + /** + * @param id A unique id for this launchable target. + * @param info The ShortcutInfo that represents this launchable target. + * @hide + */ + @SystemApi + @TestApi + public Builder(@NonNull AppTargetId id, @NonNull ShortcutInfo info) { + mId = Preconditions.checkNotNull(id); + mShortcutInfo = Preconditions.checkNotNull(info); + mPackageName = info.getPackage(); + mUser = info.getUserHandle(); + } + + /** + * @deprecated Use the appropriate constructor. + * @hide */ @NonNull + @Deprecated public Builder setTarget(@NonNull String packageName, @NonNull UserHandle user) { if (mPackageName != null) { throw new IllegalArgumentException("Target is already set"); @@ -232,11 +257,11 @@ public final class AppTarget implements Parcelable { } /** - * Sets the target to be a ShortcutInfo. - * - * @throws IllegalArgumentException is the target is already set + * @deprecated Use the appropriate constructor. + * @hide */ @NonNull + @Deprecated public Builder setTarget(@NonNull ShortcutInfo info) { setTarget(info.getPackage(), info.getUserHandle()); mShortcutInfo = Preconditions.checkNotNull(info); @@ -244,7 +269,7 @@ public final class AppTarget implements Parcelable { } /** - * Sets the className for the target + * Sets the className for the target. */ @NonNull public Builder setClassName(@NonNull String className) { @@ -253,7 +278,7 @@ public final class AppTarget implements Parcelable { } /** - * Sets the rank of the for the target. + * Sets the rank of the target. */ @NonNull public Builder setRank(@IntRange(from = 0) int rank) { @@ -274,7 +299,7 @@ public final class AppTarget implements Parcelable { @NonNull public AppTarget build() { if (mPackageName == null) { - throw new IllegalStateException("No target set"); + throw new IllegalStateException("No target is set"); } return new AppTarget(mId, mPackageName, mUser, mShortcutInfo, mClassName, mRank); } diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index db22f8d1de87..cdf5d4912ad5 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -66,6 +66,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public void preExecute(ClientTransactionHandler client, IBinder token) { + client.countLaunchingActivities(1); client.updateProcessState(mProcState, false); client.updatePendingConfiguration(mCurConfig); } @@ -82,6 +83,12 @@ public class LaunchActivityItem extends ClientTransactionItem { Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } + @Override + public void postExecute(ClientTransactionHandler client, IBinder token, + PendingTransactionActions pendingActions) { + client.countLaunchingActivities(-1); + } + // ObjectPoolItem implementation diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java index fa3d3b8dea0c..941e9e2ecce5 100644 --- a/core/java/android/attention/AttentionManagerInternal.java +++ b/core/java/android/attention/AttentionManagerInternal.java @@ -46,13 +46,6 @@ public abstract class AttentionManagerInternal { */ public abstract void cancelAttentionCheck(AttentionCallbackInternal callback); - /** - * Disables the dependants. - * - * Example: called if the service does not have sufficient permissions to perform the task. - */ - public abstract void disableSelf(); - /** Internal interface for attention callback. */ public abstract static class AttentionCallbackInternal { /** diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java index 2174255a3619..30868bfeac66 100644 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ b/core/java/android/bluetooth/le/ScanRecord.java @@ -16,6 +16,7 @@ package android.bluetooth.le; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothUuid; @@ -97,7 +98,7 @@ public final class ScanRecord { * Returns a list of service solicitation UUIDs within the advertisement that are used to * identify the Bluetooth GATT services. */ - @Nullable + @NonNull public List<ParcelUuid> getServiceSolicitationUuids() { return mServiceSolicitationUuids; } @@ -297,9 +298,6 @@ public final class ScanRecord { if (serviceUuids.isEmpty()) { serviceUuids = null; } - if (serviceSolicitationUuids.isEmpty()) { - serviceSolicitationUuids = null; - } return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData, serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); } catch (Exception e) { diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index a41b5d3fb781..c201e4d2a129 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -17,7 +17,6 @@ package android.content; import android.annotation.UnsupportedAppUsage; -import android.content.ContentProvider; import android.database.Cursor; import android.net.Uri; import android.os.Parcel; @@ -59,6 +58,7 @@ public class ContentProviderOperation implements Parcelable { private final ContentValues mValuesBackReferences; private final Map<Integer, Integer> mSelectionArgsBackReferences; private final boolean mYieldAllowed; + private final boolean mFailureAllowed; private final static String TAG = "ContentProviderOperation"; @@ -76,6 +76,7 @@ public class ContentProviderOperation implements Parcelable { mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences; mValuesBackReferences = builder.mValuesBackReferences; mYieldAllowed = builder.mYieldAllowed; + mFailureAllowed = builder.mFailureAllowed; } private ContentProviderOperation(Parcel source) { @@ -98,6 +99,7 @@ public class ContentProviderOperation implements Parcelable { } } mYieldAllowed = source.readInt() != 0; + mFailureAllowed = source.readInt() != 0; } /** @hide */ @@ -111,6 +113,7 @@ public class ContentProviderOperation implements Parcelable { mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences; mValuesBackReferences = cpo.mValuesBackReferences; mYieldAllowed = cpo.mYieldAllowed; + mFailureAllowed = cpo.mFailureAllowed; } public void writeToParcel(Parcel dest, int flags) { @@ -157,6 +160,7 @@ public class ContentProviderOperation implements Parcelable { dest.writeInt(0); } dest.writeInt(mYieldAllowed ? 1 : 0); + dest.writeInt(mFailureAllowed ? 1 : 0); } /** @@ -212,6 +216,11 @@ public class ContentProviderOperation implements Parcelable { return mYieldAllowed; } + /** {@hide} */ + public boolean isFailureAllowed() { + return mFailureAllowed; + } + /** @hide exposed for unit tests */ @UnsupportedAppUsage public int getType() { @@ -290,19 +299,35 @@ public class ContentProviderOperation implements Parcelable { */ public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs, int numBackRefs) throws OperationApplicationException { + if (mFailureAllowed) { + try { + return applyInternal(provider, backRefs, numBackRefs); + } catch (Exception e) { + return new ContentProviderResult(e.getMessage()); + } + } else { + return applyInternal(provider, backRefs, numBackRefs); + } + } + + private ContentProviderResult applyInternal(ContentProvider provider, + ContentProviderResult[] backRefs, int numBackRefs) + throws OperationApplicationException { ContentValues values = resolveValueBackReferences(backRefs, numBackRefs); String[] selectionArgs = resolveSelectionArgsBackReferences(backRefs, numBackRefs); if (mType == TYPE_INSERT) { - Uri newUri = provider.insert(mUri, values); - if (newUri == null) { - throw new OperationApplicationException("insert failed"); + final Uri newUri = provider.insert(mUri, values); + if (newUri != null) { + return new ContentProviderResult(newUri); + } else { + throw new OperationApplicationException( + "Insert into " + mUri + " returned no result"); } - return new ContentProviderResult(newUri); } - int numRows; + final int numRows; if (mType == TYPE_DELETE) { numRows = provider.delete(mUri, mSelection, selectionArgs); } else if (mType == TYPE_UPDATE) { @@ -328,7 +353,6 @@ public class ContentProviderOperation implements Parcelable { final String expectedValue = values.getAsString(projection[i]); if (!TextUtils.equals(cursorValue, expectedValue)) { // Throw exception when expected values don't match - Log.e(TAG, this.toString()); throw new OperationApplicationException("Found value " + cursorValue + " when expected " + expectedValue + " for column " + projection[i]); @@ -340,13 +364,12 @@ public class ContentProviderOperation implements Parcelable { cursor.close(); } } else { - Log.e(TAG, this.toString()); throw new IllegalStateException("bad type, " + mType); } if (mExpectedCount != null && mExpectedCount != numRows) { - Log.e(TAG, this.toString()); - throw new OperationApplicationException("wrong number of rows: " + numRows); + throw new OperationApplicationException( + "Expected " + mExpectedCount + " rows but actual " + numRows); } return new ContentProviderResult(numRows); @@ -491,6 +514,7 @@ public class ContentProviderOperation implements Parcelable { private ContentValues mValuesBackReferences; private Map<Integer, Integer> mSelectionArgsBackReferences; private boolean mYieldAllowed; + private boolean mFailureAllowed; /** Create a {@link Builder} of a given type. The uri must not be null. */ private Builder(int type, Uri uri) { @@ -683,5 +707,11 @@ public class ContentProviderOperation implements Parcelable { mYieldAllowed = yieldAllowed; return this; } + + /** {@hide} */ + public Builder withFailureAllowed(boolean failureAllowed) { + mFailureAllowed = failureAllowed; + return this; + } } } diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java index d90173ceb3cd..b3010116a115 100644 --- a/core/java/android/content/ContentProviderResult.java +++ b/core/java/android/content/ContentProviderResult.java @@ -16,10 +16,11 @@ package android.content; -import android.content.ContentProvider; import android.net.Uri; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; /** * Contains the result of the application of a {@link ContentProviderOperation}. It is guaranteed @@ -28,26 +29,44 @@ import android.os.Parcel; public class ContentProviderResult implements Parcelable { public final Uri uri; public final Integer count; + /** {@hide} */ + public final String failure; public ContentProviderResult(Uri uri) { - if (uri == null) throw new IllegalArgumentException("uri must not be null"); - this.uri = uri; - this.count = null; + this(Preconditions.checkNotNull(uri), null, null); } public ContentProviderResult(int count) { + this(null, count, null); + } + + /** {@hide} */ + public ContentProviderResult(String failure) { + this(null, null, failure); + } + + /** {@hide} */ + public ContentProviderResult(Uri uri, Integer count, String failure) { + this.uri = uri; this.count = count; - this.uri = null; + this.failure = failure; } public ContentProviderResult(Parcel source) { - int type = source.readInt(); - if (type == 1) { - count = source.readInt(); + if (source.readInt() != 0) { + uri = Uri.CREATOR.createFromParcel(source); + } else { uri = null; + } + if (source.readInt() != 0) { + count = source.readInt(); } else { count = null; - uri = Uri.CREATOR.createFromParcel(source); + } + if (source.readInt() != 0) { + failure = source.readString(); + } else { + failure = null; } } @@ -55,37 +74,63 @@ public class ContentProviderResult implements Parcelable { public ContentProviderResult(ContentProviderResult cpr, int userId) { uri = ContentProvider.maybeAddUserId(cpr.uri, userId); count = cpr.count; + failure = cpr.failure; } + @Override public void writeToParcel(Parcel dest, int flags) { - if (uri == null) { + if (uri != null) { + dest.writeInt(1); + uri.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } + if (count != null) { dest.writeInt(1); dest.writeInt(count); } else { - dest.writeInt(2); - uri.writeToParcel(dest, 0); + dest.writeInt(0); + } + if (failure != null) { + dest.writeInt(1); + dest.writeString(failure); + } else { + dest.writeInt(0); } } + @Override public int describeContents() { return 0; } public static final @android.annotation.NonNull Creator<ContentProviderResult> CREATOR = new Creator<ContentProviderResult>() { + @Override public ContentProviderResult createFromParcel(Parcel source) { return new ContentProviderResult(source); } + @Override public ContentProviderResult[] newArray(int size) { return new ContentProviderResult[size]; } }; + @Override public String toString() { + final StringBuilder sb = new StringBuilder("ContentProviderResult("); + if (uri != null) { + sb.append("uri=" + uri + " "); + } + if (count != null) { + sb.append("count=" + count + " "); + } if (uri != null) { - return "ContentProviderResult(uri=" + uri.toString() + ")"; + sb.append("failure=" + failure + " "); } - return "ContentProviderResult(count=" + count + ")"; + sb.deleteCharAt(sb.length() - 1); + sb.append(")"); + return sb.toString(); } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 8628d32123bc..e66cd31a0641 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -643,6 +643,7 @@ public class Intent implements Parcelable, Cloneable { private static final String ATTR_CATEGORY = "category"; private static final String TAG_EXTRA = "extra"; private static final String ATTR_TYPE = "type"; + private static final String ATTR_IDENTIFIER = "ident"; private static final String ATTR_COMPONENT = "component"; private static final String ATTR_DATA = "data"; private static final String ATTR_FLAGS = "flags"; @@ -6314,6 +6315,7 @@ public class Intent implements Parcelable, Cloneable { private String mAction; private Uri mData; private String mType; + private String mIdentifier; private String mPackage; private ComponentName mComponent; private int mFlags; @@ -6359,6 +6361,7 @@ public class Intent implements Parcelable, Cloneable { this.mAction = o.mAction; this.mData = o.mData; this.mType = o.mType; + this.mIdentifier = o.mIdentifier; this.mPackage = o.mPackage; this.mComponent = o.mComponent; @@ -6678,6 +6681,11 @@ public class Intent implements Parcelable, Cloneable { intent.mType = value; } + // identifier + else if (uri.startsWith("identifier=", i)) { + intent.mIdentifier = value; + } + // launch flags else if (uri.startsWith("launchFlags=", i)) { intent.mFlags = Integer.decode(value).intValue(); @@ -7017,6 +7025,12 @@ public class Intent implements Parcelable, Cloneable { hasIntentInfo = true; } break; + case "-i": + intent.setIdentifier(cmd.getNextArgRequired()); + if (intent == baseIntent) { + hasIntentInfo = true; + } + break; case "-c": intent.addCategory(cmd.getNextArgRequired()); if (intent == baseIntent) { @@ -7375,7 +7389,7 @@ public class Intent implements Parcelable, Cloneable { public static void printIntentArgsHelp(PrintWriter pw, String prefix) { final String[] lines = new String[] { "<INTENT> specifications include these flags and arguments:", - " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]", + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>] [-i <IDENTIFIER>]", " [-c <CATEGORY> [-c <CATEGORY>] ...]", " [-n <COMPONENT_NAME>]", " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]", @@ -7557,6 +7571,18 @@ public class Intent implements Parcelable, Cloneable { } /** + * Retrieve the identifier for this Intent. If non-null, this is an arbitrary identity + * of the Intent to distinguish it from other Intents. + * + * @return The identifier of this intent or null if none is specified. + * + * @see #setIdentifier + */ + public @Nullable String getIdentifier() { + return mIdentifier; + } + + /** * Check if a category exists in the intent. * * @param category The category to check. @@ -8576,6 +8602,28 @@ public class Intent implements Parcelable, Cloneable { } /** + * Set an identifier for this Intent. If set, this provides a unique identity for this Intent, + * allowing it to be unique from other Intents that would otherwise look the same. In + * particular, this will be used by {@link #filterEquals(Intent)} to determine if two + * Intents are the same as with other fields like {@link #setAction}. However, unlike those + * fields, the identifier is <em>never</em> used for matching against an {@link IntentFilter}; + * it is as if the identifier has not been set on the Intent. + * + * @param identifier The identifier for this Intent. The contents of the string have no + * meaning to the system, except whether they are exactly the same as + * another identifier. + * + * @return Returns the same Intent object, for chaining multiple calls + * into a single statement. + * + * @see #getIdentifier + */ + public @NonNull Intent setIdentifier(@Nullable String identifier) { + mIdentifier = identifier; + return this; + } + + /** * Add a new category to the intent. Categories provide additional detail * about the action the intent performs. When resolving an intent, only * activities that provide <em>all</em> of the requested categories will be @@ -9693,6 +9741,12 @@ public class Intent implements Parcelable, Cloneable { public static final int FILL_IN_CLIP_DATA = 1<<7; /** + * Use with {@link #fillIn} to allow the current identifier value to be + * overwritten, even if it is already set. + */ + public static final int FILL_IN_IDENTIFIER = 1<<8; + + /** * Copy the contents of <var>other</var> in to this object, but only * where fields are not defined by this object. For purposes of a field * being defined, the following pieces of data in the Intent are @@ -9702,6 +9756,7 @@ public class Intent implements Parcelable, Cloneable { * <li> action, as set by {@link #setAction}. * <li> data Uri and MIME type, as set by {@link #setData(Uri)}, * {@link #setType(String)}, or {@link #setDataAndType(Uri, String)}. + * <li> identifier, as set by {@link #setIdentifier}. * <li> categories, as set by {@link #addCategory}. * <li> package, as set by {@link #setPackage}. * <li> component, as set by {@link #setComponent(ComponentName)} or @@ -9713,8 +9768,8 @@ public class Intent implements Parcelable, Cloneable { * </ul> * * <p>In addition, you can use the {@link #FILL_IN_ACTION}, - * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE}, - * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, + * {@link #FILL_IN_DATA}, {@link #FILL_IN_IDENTIFIER}, {@link #FILL_IN_CATEGORIES}, + * {@link #FILL_IN_PACKAGE}, {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, * {@link #FILL_IN_SELECTOR}, and {@link #FILL_IN_CLIP_DATA} to override * the restriction where the corresponding field will not be replaced if * it is already set. @@ -9758,6 +9813,11 @@ public class Intent implements Parcelable, Cloneable { changes |= FILL_IN_DATA; mayHaveCopiedUris = true; } + if (other.mIdentifier != null + && (mIdentifier == null || (flags&FILL_IN_IDENTIFIER) != 0)) { + mIdentifier = other.mIdentifier; + changes |= FILL_IN_IDENTIFIER; + } if (other.mCategories != null && (mCategories == null || (flags&FILL_IN_CATEGORIES) != 0)) { if (other.mCategories != null) { @@ -9871,9 +9931,11 @@ public class Intent implements Parcelable, Cloneable { /** * Determine if two intents are the same for the purposes of intent - * resolution (filtering). That is, if their action, data, type, + * resolution (filtering). That is, if their action, data, type, identity, * class, and categories are the same. This does <em>not</em> compare - * any extra data included in the intents. + * any extra data included in the intents. Note that technically when actually + * matching against an {@link IntentFilter} the identifier is ignored, while here + * it is directly compared for equality like the other fields. * * @param other The other Intent to compare against. * @@ -9887,6 +9949,7 @@ public class Intent implements Parcelable, Cloneable { if (!Objects.equals(this.mAction, other.mAction)) return false; if (!Objects.equals(this.mData, other.mData)) return false; if (!Objects.equals(this.mType, other.mType)) return false; + if (!Objects.equals(this.mIdentifier, other.mIdentifier)) return false; if (!Objects.equals(this.mPackage, other.mPackage)) return false; if (!Objects.equals(this.mComponent, other.mComponent)) return false; if (!Objects.equals(this.mCategories, other.mCategories)) return false; @@ -9913,6 +9976,9 @@ public class Intent implements Parcelable, Cloneable { if (mType != null) { code += mType.hashCode(); } + if (mIdentifier != null) { + code += mIdentifier.hashCode(); + } if (mPackage != null) { code += mPackage.hashCode(); } @@ -10005,6 +10071,13 @@ public class Intent implements Parcelable, Cloneable { first = false; b.append("typ=").append(mType); } + if (mIdentifier != null) { + if (!first) { + b.append(' '); + } + first = false; + b.append("id=").append(mIdentifier); + } if (mFlags != 0) { if (!first) { b.append(' '); @@ -10276,6 +10349,9 @@ public class Intent implements Parcelable, Cloneable { if (mType != null) { uri.append("type=").append(Uri.encode(mType, "/")).append(';'); } + if (mIdentifier != null) { + uri.append("identifier=").append(Uri.encode(mIdentifier, "/")).append(';'); + } if (mFlags != 0) { uri.append("launchFlags=0x").append(Integer.toHexString(mFlags)).append(';'); } @@ -10326,6 +10402,7 @@ public class Intent implements Parcelable, Cloneable { out.writeString(mAction); Uri.writeToParcel(out, mData); out.writeString(mType); + out.writeString(mIdentifier); out.writeInt(mFlags); out.writeString(mPackage); ComponentName.writeToParcel(mComponent, out); @@ -10383,6 +10460,7 @@ public class Intent implements Parcelable, Cloneable { setAction(in.readString()); mData = Uri.CREATOR.createFromParcel(in); mType = in.readString(); + mIdentifier = in.readString(); mFlags = in.readInt(); mPackage = in.readString(); mComponent = ComponentName.readFromParcel(in); @@ -10445,6 +10523,8 @@ public class Intent implements Parcelable, Cloneable { String mimeType = sa.getString(com.android.internal.R.styleable.Intent_mimeType); intent.setDataAndType(data != null ? Uri.parse(data) : null, mimeType); + intent.setIdentifier(sa.getString(com.android.internal.R.styleable.Intent_identifier)); + String packageName = sa.getString(com.android.internal.R.styleable.Intent_targetPackage); String className = sa.getString(com.android.internal.R.styleable.Intent_targetClass); if (packageName != null && className != null) { @@ -10499,6 +10579,9 @@ public class Intent implements Parcelable, Cloneable { if (mType != null) { out.attribute(null, ATTR_TYPE, mType); } + if (mIdentifier != null) { + out.attribute(null, ATTR_IDENTIFIER, mIdentifier); + } if (mComponent != null) { out.attribute(null, ATTR_COMPONENT, mComponent.flattenToShortString()); } @@ -10529,6 +10612,8 @@ public class Intent implements Parcelable, Cloneable { intent.setData(Uri.parse(attrValue)); } else if (ATTR_TYPE.equals(attrName)) { intent.setType(attrValue); + } else if (ATTR_IDENTIFIER.equals(attrName)) { + intent.setIdentifier(attrValue); } else if (ATTR_COMPONENT.equals(attrName)) { intent.setComponent(ComponentName.unflattenFromString(attrValue)); } else if (ATTR_FLAGS.equals(attrName)) { diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 6c72a9a1c0c2..6ce682843ed5 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -841,13 +841,12 @@ public class PackageInstaller { * installation (for example, the same split name), the APK in this session * will replace the existing APK. * <p> - * In such a case that multiple packages need to be commited simultaneously, + * In such a case that multiple packages need to be committed simultaneously, * multiple sessions can be referenced by a single multi-package session. * This session is created with no package name and calling - * {@link SessionParams#setMultiPackage()} with {@code true}. The - * individual session IDs can be added with {@link #addChildSessionId(int)} - * and commit of the multi-package session will result in all child sessions - * being committed atomically. + * {@link SessionParams#setMultiPackage()}. The individual session IDs can be + * added with {@link #addChildSessionId(int)} and commit of the multi-package + * session will result in all child sessions being committed atomically. */ public static class Session implements Closeable { /** {@hide} */ diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 6035f40e768a..7349f0cbe55d 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -93,8 +93,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } @Override // binder call - public void onAuthenticationSucceeded(long deviceId, Face face) { - mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, face).sendToTarget(); + public void onAuthenticationSucceeded(long deviceId, Face face, int userId) { + mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, face).sendToTarget(); } @Override // binder call @@ -168,6 +168,44 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { + authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId()); + } + + /** + * Use the provided handler thread for events. + */ + private void useHandler(Handler handler) { + if (handler != null) { + mHandler = new MyHandler(handler.getLooper()); + } else if (mHandler.getLooper() != mContext.getMainLooper()) { + mHandler = new MyHandler(mContext.getMainLooper()); + } + } + + /** + * Request authentication of a crypto object. This call operates the face recognition hardware + * and starts capturing images. It terminates when + * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or + * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at + * which point the object is no longer valid. The operation can be canceled by using the + * provided cancel object. + * + * @param crypto object associated with the call or null if none required. + * @param cancel an object that can be used to cancel authentication + * @param flags optional flags; should be 0 + * @param callback an object to receive authentication events + * @param handler an optional handler to handle callback events + * @param userId userId to authenticate for + * @throws IllegalArgumentException if the crypto operation is not supported or is not backed + * by + * <a href="{@docRoot}training/articles/keystore.html">Android + * Keystore facility</a>. + * @throws IllegalStateException if the crypto primitive is not initialized. + * @hide + */ + public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, + int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler, + int userId) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } @@ -187,7 +225,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mAuthenticationCallback = callback; mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; - mService.authenticate(mToken, sessionId, mContext.getUserId(), mServiceReceiver, + mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, mContext.getOpPackageName()); } catch (RemoteException e) { Log.w(TAG, "Remote exception while authenticating: ", e); @@ -196,24 +234,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan // try again later. callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */)); + 0 /* vendorCode */)); } } } } /** - * Use the provided handler thread for events. - */ - private void useHandler(Handler handler) { - if (handler != null) { - mHandler = new MyHandler(handler.getLooper()); - } else if (mHandler.getLooper() != mContext.getMainLooper()) { - mHandler = new MyHandler(mContext.getMainLooper()); - } - } - - /** * Request face authentication enrollment. This call operates the face authentication hardware * and starts capturing images. Progress will be indicated by callbacks to the * {@link EnrollmentCallback} object. It terminates when diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl index 217690273969..10f9c435c415 100644 --- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl +++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl @@ -24,7 +24,7 @@ import android.hardware.face.Face; oneway interface IFaceServiceReceiver { void onEnrollResult(long deviceId, int faceId, int remaining); void onAcquired(long deviceId, int acquiredInfo, int vendorCode); - void onAuthenticationSucceeded(long deviceId, in Face face); + void onAuthenticationSucceeded(long deviceId, in Face face, int userId); void onAuthenticationFailed(long deviceId); void onError(long deviceId, int error, int vendorCode); void onRemoved(long deviceId, int faceId, int remaining); diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index aff385dc23e1..d05ba799205c 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -428,17 +428,33 @@ public final class HdmiControlManager { } /** - * Get a snapshot of the real-time status of the remote devices. + * Get a snapshot of the real-time status of the devices on the CEC bus. * - * <p>This only applies to devices with multiple HDMI inputs. + * <p>This only applies to devices with switch functionality, which are devices with one + * or more than one HDMI inputs. * - * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices. An empty - * list will be returned if there is none. + * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices on the CEC bus. An + * empty list will be returned if there is none. * * @hide */ + @NonNull + @SystemApi + public List<HdmiDeviceInfo> getConnectedDevices() { + try { + return mService.getDeviceList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #getConnectedDevices()} instead. + */ + @Deprecated @SystemApi - @Nullable public List<HdmiDeviceInfo> getConnectedDevicesList() { try { return mService.getDeviceList(); @@ -448,7 +464,8 @@ public final class HdmiControlManager { } /** - * Power off the target device by sending CEC commands. + * Power off the target device by sending CEC commands. Note that this device can't be the + * current device itself. * * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * @@ -457,6 +474,23 @@ public final class HdmiControlManager { * @hide */ @SystemApi + public void powerOffDevice(@NonNull HdmiDeviceInfo deviceInfo) { + Preconditions.checkNotNull(deviceInfo); + try { + mService.powerOffRemoteDevice( + deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #powerOffDevice(deviceInfo)} instead. + */ + @Deprecated + @SystemApi public void powerOffRemoteDevice(@NonNull HdmiDeviceInfo deviceInfo) { Preconditions.checkNotNull(deviceInfo); try { @@ -468,7 +502,8 @@ public final class HdmiControlManager { } /** - * Power on the target device by sending CEC commands. + * Power on the target device by sending CEC commands. Note that this device can't be the + * current device itself. * * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * @@ -476,6 +511,23 @@ public final class HdmiControlManager { * * @hide */ + public void powerOnDevice(HdmiDeviceInfo deviceInfo) { + Preconditions.checkNotNull(deviceInfo); + try { + mService.powerOnRemoteDevice( + deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #powerOnDevice(deviceInfo)} instead. + */ + @Deprecated + @SystemApi public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) { Preconditions.checkNotNull(deviceInfo); try { @@ -487,15 +539,35 @@ public final class HdmiControlManager { } /** - * Request the target device to be the new Active Source by sending CEC commands. + * Request the target device to be the new Active Source by sending CEC commands. Note that + * this device can't be the current device itself. * * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * + * <p>If the target device responds to the command, the users should see the target device + * streaming on their TVs. + * * @param deviceInfo HdmiDeviceInfo of the target device * * @hide */ @SystemApi + public void setActiveSource(@NonNull HdmiDeviceInfo deviceInfo) { + Preconditions.checkNotNull(deviceInfo); + try { + mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #setActiveSource(deviceInfo)} instead. + */ + @Deprecated + @SystemApi public void requestRemoteDeviceToBecomeActiveSource(@NonNull HdmiDeviceInfo deviceInfo) { Preconditions.checkNotNull(deviceInfo); try { @@ -556,7 +628,7 @@ public final class HdmiControlManager { } /** - * Check if the target remote device is connected to the current device. + * Check if the target device is connected to the current device. * * <p>The API also returns true if the current device is the target. * @@ -567,6 +639,27 @@ public final class HdmiControlManager { * @hide */ @SystemApi + public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) { + Preconditions.checkNotNull(targetDevice); + mPhysicalAddress = getPhysicalAddress(); + if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { + return false; + } + int targetPhysicalAddress = targetDevice.getPhysicalAddress(); + if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { + return false; + } + return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress) + != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE; + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #isDeviceConnected(targetDevice)} instead. + */ + @Deprecated + @SystemApi public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) { Preconditions.checkNotNull(targetDevice); mPhysicalAddress = getPhysicalAddress(); diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java index 0604f6a69d00..4b02085726f1 100644 --- a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java +++ b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java @@ -374,4 +374,15 @@ public final class MultiClientInputMethodServiceDelegate { public boolean isUidAllowedOnDisplay(int displayId, int uid) { return mImpl.isUidAllowedOnDisplay(displayId, uid); } + + /** + * Can be called by MSIME to activate/deactivate a client when it is gaining/losing focus + * respectively. + * + * @param clientId client ID to activate/deactivate. + * @param active {@code true} to activate a client. + */ + public void setActive(int clientId, boolean active) { + mImpl.setActive(clientId, active); + } } diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java index bbe3a7fe1b31..04db8d625806 100644 --- a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java +++ b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java @@ -190,4 +190,8 @@ final class MultiClientInputMethodServiceDelegateImpl { boolean isUidAllowedOnDisplay(int displayId, int uid) { return mPrivOps.isUidAllowedOnDisplay(displayId, uid); } + + void setActive(int clientId, boolean active) { + mPrivOps.setActive(clientId, active); + } } diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java index b8d7cf167ca8..a55d9d00414f 100644 --- a/core/java/android/net/SntpClient.java +++ b/core/java/android/net/SntpClient.java @@ -20,6 +20,8 @@ import android.annotation.UnsupportedAppUsage; import android.os.SystemClock; import android.util.Log; +import com.android.internal.util.TrafficStatsConstants; + import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; @@ -99,7 +101,8 @@ public class SntpClient { public boolean requestTime(InetAddress address, int port, int timeout, Network network) { DatagramSocket socket = null; - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NTP); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_NTP); try { socket = new DatagramSocket(); network.bindSocket(socket); diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 49c6f74b1a34..4332d8abbce3 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -90,6 +90,42 @@ public class TrafficStats { public static final int UID_TETHERING = -5; /** + * Tag values in this range are reserved for the network stack. The network stack is + * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline + * module separate process, and as the system UID otherwise. + */ + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00; + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF; + + /** + * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services + * like DownloadManager when performing traffic on behalf of an application. + */ + // Please note there is no enforcement of these constants, so do not rely on them to + // determine that the caller is a system caller. + /** @hide */ + @SystemApi + public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00; + /** @hide */ + @SystemApi + public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F; + + /** + * Tag values between these ranges are reserved for the network stack to do traffic + * on behalf of applications. It is a subrange of the range above. + */ + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80; + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F; + + /** * Default tag value for {@link DownloadManager} traffic. * * @hide @@ -127,26 +163,9 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_APP = 0xFFFFFF05; + // TODO : remove this constant when Wifi code is updated /** @hide */ - @SystemApi - @TestApi - public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40; - /** @hide */ - public static final int TAG_SYSTEM_NTP = 0xFFFFFF41; - /** @hide */ - @SystemApi - @TestApi public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; - /** @hide */ - public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43; - /** @hide */ - public static final int TAG_SYSTEM_GPS = 0xFFFFFF44; - /** @hide */ - public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; - /** @hide */ - @SystemApi - @TestApi - public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46; private static INetworkStatsService sStatsService; diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 166de3fde741..6c498c736854 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -493,6 +493,7 @@ public final class DeviceConfig { * @param onPropertyChangedListener The listener to add. * @hide * @see #removeOnPropertyChangedListener(OnPropertyChangedListener) + * @removed */ @SystemApi @TestApi @@ -569,6 +570,7 @@ public final class DeviceConfig { * @param onPropertyChangedListener The listener to remove. * @hide * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener) + * @removed */ @SystemApi @TestApi @@ -737,6 +739,7 @@ public final class DeviceConfig { * Override {@link #onPropertyChanged(String, String, String)} to handle callbacks for changes. * * @hide + * @removed */ @SystemApi @TestApi diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index da19d59367a0..bff8328defa0 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -31,7 +31,6 @@ import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.AppGlobals; import android.content.ClipData; -import android.content.ContentInterface; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentUris; @@ -968,6 +967,13 @@ public final class MediaStore { public static final String DATE_MODIFIED = "date_modified"; /** + * The time the media item was taken. + */ + @CurrentTimeMillisLong + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + public static final String DATE_TAKEN = "datetaken"; + + /** * The MIME type of the media item. * <p> * This is typically defined based on the file extension of the media @@ -1117,6 +1123,38 @@ public final class MediaStore { public static final String SECONDARY_DIRECTORY = "secondary_directory"; /** + * The primary bucket ID of this media item. This can be useful to + * present the user a first-level clustering of related media items. + * This is a read-only column that is automatically computed. + */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + public static final String BUCKET_ID = "bucket_id"; + + /** + * The primary bucket display name of this media item. This can be + * useful to present the user a first-level clustering of related + * media items. This is a read-only column that is automatically + * computed. + */ + @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) + public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; + + /** + * The group ID of this media item. This can be useful to present + * the user a grouping of related media items, such a burst of + * images, or a {@code JPG} and {@code DNG} version of the same + * image. + * <p> + * This is a read-only column that is automatically computed based + * on the first portion of the filename. For example, + * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG} + * will have the same {@link #GROUP_ID} because the first portion of + * their filenames is identical. + */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + public static final String GROUP_ID = "group_id"; + + /** * The "document ID" GUID as defined by the <em>XMP Media * Management</em> standard, extracted from any XMP metadata contained * within this media item. The value is {@code null} when no metadata @@ -1152,6 +1190,20 @@ public final class MediaStore { */ @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String ORIGINAL_DOCUMENT_ID = "original_document_id"; + + /** + * The duration of the media item. + */ + @DurationMillisLong + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + public static final String DURATION = "duration"; + + /** + * The orientation for the media item, expressed in degrees. For + * example, 0, 90, 180, or 270 degrees. + */ + @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + public static final String ORIENTATION = "orientation"; } /** @@ -1357,7 +1409,10 @@ public final class MediaStore { /** * The description of the download. + * + * @removed */ + @Deprecated @Column(Cursor.FIELD_TYPE_STRING) String DESCRIPTION = "description"; } @@ -1573,18 +1628,9 @@ public final class MediaStore { @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true) public static final String LONGITUDE = "longitude"; - /** - * The time the media item was taken. - */ - @CurrentTimeMillisLong - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String DATE_TAKEN = "datetaken"; - - /** - * The orientation for the image expressed as degrees. - * Only degrees 0, 90, 180, 270 will work. - */ - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String ORIENTATION = "orientation"; /** @@ -1598,36 +1644,11 @@ public final class MediaStore { @Column(Cursor.FIELD_TYPE_INTEGER) public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; - /** - * The primary bucket ID of this media item. This can be useful to - * present the user a first-level clustering of related media items. - * This is a read-only column that is automatically computed. - */ - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String BUCKET_ID = "bucket_id"; - - /** - * The primary bucket display name of this media item. This can be - * useful to present the user a first-level clustering of related - * media items. This is a read-only column that is automatically - * computed. - */ - @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) + /** @removed promoted to parent interface */ public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; - - /** - * The group ID of this media item. This can be useful to present - * the user a grouping of related media items, such a burst of - * images, or a {@code JPG} and {@code DNG} version of the same - * image. - * <p> - * This is a read-only column that is automatically computed based - * on the first portion of the filename. For example, - * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG} - * will have the same {@link #GROUP_ID} because the first portion of - * their filenames is identical. - */ - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String GROUP_ID = "group_id"; } @@ -2048,11 +2069,7 @@ public final class MediaStore { @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) public static final String TITLE_KEY = "title_key"; - /** - * The duration of the audio item. - */ - @DurationMillisLong - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String DURATION = "duration"; /** @@ -2885,12 +2902,7 @@ public final class MediaStore { * Video metadata columns. */ public interface VideoColumns extends MediaColumns { - - /** - * The duration of the video item. - */ - @DurationMillisLong - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String DURATION = "duration"; /** @@ -2965,11 +2977,7 @@ public final class MediaStore { @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true) public static final String LONGITUDE = "longitude"; - /** - * The time the media item was taken. - */ - @CurrentTimeMillisLong - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String DATE_TAKEN = "datetaken"; /** @@ -2983,36 +2991,11 @@ public final class MediaStore { @Column(Cursor.FIELD_TYPE_INTEGER) public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; - /** - * The primary bucket ID of this media item. This can be useful to - * present the user a first-level clustering of related media items. - * This is a read-only column that is automatically computed. - */ - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String BUCKET_ID = "bucket_id"; - - /** - * The primary bucket display name of this media item. This can be - * useful to present the user a first-level clustering of related - * media items. This is a read-only column that is automatically - * computed. - */ - @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true) + /** @removed promoted to parent interface */ public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; - - /** - * The group ID of this media item. This can be useful to present - * the user a grouping of related media items, such a burst of - * images, or a {@code JPG} and {@code DNG} version of the same - * image. - * <p> - * This is a read-only column that is automatically computed based - * on the first portion of the filename. For example, - * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG} - * will have the same {@link #GROUP_ID} because the first portion of - * their filenames is identical. - */ - @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true) + /** @removed promoted to parent interface */ public static final String GROUP_ID = "group_id"; /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0491c732db81..488f41719454 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -955,18 +955,16 @@ public final class Settings { "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; /** - * Activity Action: Open the advanced power usage details page of an associated app. + * Activity Action: Open the battery details page of an associated app. * <p> * Input: Intent's data URI set with an application name, using the * "package" schema (like "package:com.my.app") * <p> * Output: Nothing. - * - * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL = - "android.settings.VIEW_ADVANCED_POWER_USAGE_DETAIL"; + public static final String ACTION_APP_BATTERY_SETTINGS = + "android.settings.APP_BATTERY_SETTINGS"; /** * Activity Action: Show screen for controlling background data @@ -1533,6 +1531,9 @@ public final class Settings { /** * Activity Action: Show More default apps settings. * <p> + * If a Settings activity handles this intent action, a "More defaults" entry will be shown in + * the Default apps settings, and clicking it will launch that activity. + * <p> * In some cases, a matching Activity may not exist, so ensure you safeguard against this. * <p> * Input: Nothing. @@ -5801,6 +5802,14 @@ public final class Settings { "autofill_field_classification"; /** + * Boolean indicating if the dark mode dialog shown on first toggle has been seen. + * + * @hide + */ + public static final String DARK_MODE_DIALOG_SEEN = + "dark_mode_dialog_seen"; + + /** * Defines value returned by {@link android.service.autofill.UserData#getMaxUserDataSize()}. * * @hide @@ -8139,7 +8148,14 @@ public final class Settings { public static final String FACE_UNLOCK_ATTENTION_REQUIRED = "face_unlock_attention_required"; - private static final Validator FACE_UNLOCK_ATTENTION_REQUIRED_VALIDATOR = BOOLEAN_VALIDATOR; + /** + * Whether or not face unlock requires a diverse set of poses during enrollment. This is a + * cached value, the source of truth is obtained through the HAL. + * @hide + */ + public static final String FACE_UNLOCK_DIVERSITY_REQUIRED = + "face_unlock_diversity_required"; + /** * Whether or not face unlock is allowed for apps (through BiometricPrompt). @@ -8797,7 +8813,6 @@ public final class Settings { AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_DISMISSES_KEYGUARD, - FACE_UNLOCK_ATTENTION_REQUIRED, FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, ASSIST_GESTURE_ENABLED, @@ -8842,6 +8857,7 @@ public final class Settings { SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_CALL_GESTURE_COUNT, SILENCE_TIMER_GESTURE_COUNT, + DARK_MODE_DIALOG_SEEN }; /** @@ -8964,8 +8980,6 @@ public final class Settings { VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR); VALIDATORS.put(FACE_UNLOCK_DISMISSES_KEYGUARD, FACE_UNLOCK_DISMISSES_KEYGUARD_VALIDATOR); - VALIDATORS.put(FACE_UNLOCK_ATTENTION_REQUIRED, - FACE_UNLOCK_ATTENTION_REQUIRED_VALIDATOR); VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR); VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR); @@ -9024,6 +9038,7 @@ public final class Settings { VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR); VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR); VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR); + VALIDATORS.put(DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR); } /** diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java index 6172ce501590..49ab5db74b87 100644 --- a/core/java/android/service/attention/AttentionService.java +++ b/core/java/android/service/attention/AttentionService.java @@ -21,13 +21,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.Service; -import android.attention.AttentionManagerInternal; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import com.android.internal.util.Preconditions; -import com.android.server.LocalServices; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -132,19 +130,6 @@ public abstract class AttentionService extends Service { } /** - * Disables the dependants. - * - * Example: called if the service does not have sufficient permissions to perform the task. - */ - public final void disableSelf() { - AttentionManagerInternal attentionManager = LocalServices.getService( - AttentionManagerInternal.class); - if (attentionManager != null) { - attentionManager.disableSelf(); - } - } - - /** * Checks the user attention and calls into the provided callback. * * @param callback the callback to return the result to diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 5be73b92fbc0..02ce87324a4f 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -46,9 +46,9 @@ import android.view.contentcapture.ContentCaptureEvent; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; import android.view.contentcapture.ContentCaptureSessionId; +import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.IContentCaptureDirectManager; import android.view.contentcapture.MainContentCaptureSession; -import android.view.contentcapture.UserDataRemovalRequest; import com.android.internal.os.IResultReceiver; @@ -86,11 +86,28 @@ public abstract class ContentCaptureService extends Service { * <code><{@link * android.R.styleable#ContentCaptureService content-capture-service}></code> tag. * - * <p>This is a a sample XML file configuring a ContentCaptureService: - * <pre> <content-capture-service - * android:settingsActivity="foo.bar.SettingsActivity" - * . . . - * /></pre> + * <p>Here's an example of how to use it on {@code AndroidManifest.xml}: + * + * <pre> + * <service android:name=".MyContentCaptureService" + * android:permission="android.permission.BIND_CONTENT_CAPTURE_SERVICE"> + * <intent-filter> + * <action android:name="android.service.contentcapture.ContentCaptureService" /> + * </intent-filter> + * + * <meta-data + * android:name="android.content_capture" + * android:resource="@xml/my_content_capture_service"/> + * </service> + * </pre> + * + * <p>And then on {@code res/xml/my_content_capture_service.xml}: + * + * <pre> + * <content-capture-service xmlns:android="http://schemas.android.com/apk/res/android" + * android:settingsActivity="my.package.MySettingsActivity"> + * </content-capture-service> + * </pre> */ public static final String SERVICE_META_DATA = "android.content_capture"; @@ -138,7 +155,7 @@ public abstract class ContentCaptureService extends Service { } @Override - public void onUserDataRemovalRequest(UserDataRemovalRequest request) { + public void onDataRemovalRequest(DataRemovalRequest request) { mHandler.sendMessage( obtainMessage(ContentCaptureService::handleOnUserDataRemovalRequest, ContentCaptureService.this, request)); @@ -288,12 +305,12 @@ public abstract class ContentCaptureService extends Service { } /** - * Notifies the service that the app requested to remove data associated with the user. + * Notifies the service that the app requested to remove content capture data. * - * @param request the user data requested to be removed + * @param request the content capture data requested to be removed */ - public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) { - if (sVerbose) Log.v(TAG, "onUserDataRemovalRequest()"); + public void onDataRemovalRequest(@NonNull DataRemovalRequest request) { + if (sVerbose) Log.v(TAG, "onDataRemovalRequest()"); } /** @@ -449,8 +466,8 @@ public abstract class ContentCaptureService extends Service { onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId)); } - private void handleOnUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) { - onUserDataRemovalRequest(request); + private void handleOnUserDataRemovalRequest(@NonNull DataRemovalRequest request) { + onDataRemovalRequest(request); } private void handleOnActivityEvent(@NonNull ActivityEvent event) { diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl index 03e1b7857837..a7578af94004 100644 --- a/core/java/android/service/contentcapture/IContentCaptureService.aidl +++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl @@ -21,7 +21,7 @@ import android.os.IBinder; import android.service.contentcapture.ActivityEvent; import android.service.contentcapture.SnapshotData; import android.view.contentcapture.ContentCaptureContext; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import com.android.internal.os.IResultReceiver; @@ -39,6 +39,6 @@ oneway interface IContentCaptureService { in IResultReceiver clientReceiver, int initialState); void onSessionFinished(int sessionId); void onActivitySnapshot(int sessionId, in SnapshotData snapshotData); - void onUserDataRemovalRequest(in UserDataRemovalRequest request); + void onDataRemovalRequest(in DataRemovalRequest request); void onActivityEvent(in ActivityEvent event); } diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index 2288106d8351..d2f22bfac84a 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -418,12 +418,15 @@ public abstract class EuiccService extends Service { * bit map, and original the card Id. The result code may be one of the predefined * {@code RESULT_} constants or any implementation-specific code starting with * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values - * defined in {@code RESOLVABLE_ERROR_}. + * defined in {@code RESOLVABLE_ERROR_}. A subclass should override this method. Otherwise, + * this method does nothing and returns null by default. * @see android.telephony.euicc.EuiccManager#downloadSubscription */ - public abstract DownloadSubscriptionResult onDownloadSubscription(int slotId, + public DownloadSubscriptionResult onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, - boolean forceDeactivateSim, @Nullable Bundle resolvedBundle); + boolean forceDeactivateSim, @Nullable Bundle resolvedBundle) { + return null; + } /** * Download the given subscription. @@ -439,14 +442,14 @@ public abstract class EuiccService extends Service { * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#downloadSubscription * - * @deprecated From Q, please use the above - * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. + * @deprecated From Q, a subclass should use and override the above + * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. The + * default return value for this one is Integer.MIN_VALUE. */ @Deprecated public @Result int onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim) { - throw new UnsupportedOperationException("onDownloadSubscription(int, " - + "DownloadableSubscription, boolean, boolean) is deprecated."); + return Integer.MIN_VALUE; } /** diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index e3e63e539591..0de17ca3b960 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -17,7 +17,6 @@ package android.service.voice; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.UnsupportedAppUsage; import android.app.Service; @@ -41,6 +40,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Set; @@ -211,11 +211,11 @@ public class VoiceInteractionService extends Service { * * @param voiceActions A set of checked voice actions. * @return Returns a subset of checked voice actions. Additional voice actions in the - * returned set will be ignored. Returns null or empty set if no actions are supported. + * returned set will be ignored. Returns empty set if no actions are supported. */ - @Nullable + @NonNull public Set<String> onGetSupportedVoiceActions(@NonNull Set<String> voiceActions) { - return null; + return Collections.emptySet(); } @Override @@ -272,7 +272,7 @@ public class VoiceInteractionService extends Service { try { Set<String> voiceActionsSet = new ArraySet<>(voiceActions); Set<String> resultSet = onGetSupportedVoiceActions(voiceActionsSet); - callback.onComplete(resultSet == null ? null : new ArrayList<>(resultSet)); + callback.onComplete(new ArrayList<>(resultSet)); } catch (RemoteException e) { } } diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 6f274477431f..5b5f3b843c50 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -123,7 +123,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked - * from an Android automotive system Ui. + * from an Android automotive system UI. */ public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 1 << 7; diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index f2747cf426fa..1bcfc05224ca 100755 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -34,11 +34,32 @@ public class DisplayMetrics { public static final int DENSITY_LOW = 120; /** + * Intermediate density for screens that sit between {@link #DENSITY_LOW} (120dpi) and + * {@link #DENSITY_MEDIUM} (160dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_MEDIUM} assets for them. + */ + public static final int DENSITY_140 = 140; + + /** * Standard quantized DPI for medium-density screens. */ public static final int DENSITY_MEDIUM = 160; /** + * Intermediate density for screens that sit between {@link #DENSITY_MEDIUM} (160dpi) and + * {@link #DENSITY_HIGH} (240dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_HIGH} assets for them. + */ + public static final int DENSITY_180 = 180; + + /** + * Intermediate density for screens that sit between {@link #DENSITY_MEDIUM} (160dpi) and + * {@link #DENSITY_HIGH} (240dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_HIGH} assets for them. + */ + public static final int DENSITY_200 = 200; + + /** * This is a secondary density, added for some common screen configurations. * It is recommended that applications not generally target this as a first * class density -- that is, don't supply specific graphics for this @@ -58,6 +79,13 @@ public class DisplayMetrics { public static final int DENSITY_TV = 213; /** + * Intermediate density for screens that sit between {@link #DENSITY_MEDIUM} (160dpi) and + * {@link #DENSITY_HIGH} (240dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_HIGH} assets for them. + */ + public static final int DENSITY_220 = 220; + + /** * Standard quantized DPI for high-density screens. */ public static final int DENSITY_HIGH = 240; diff --git a/core/java/android/view/InputMonitor.java b/core/java/android/view/InputMonitor.java index 693f2873522c..bbd27dc45779 100644 --- a/core/java/android/view/InputMonitor.java +++ b/core/java/android/view/InputMonitor.java @@ -22,6 +22,13 @@ import android.os.Parcelable; import android.os.RemoteException; /** + * An {@code InputMonitor} allows privileged applications and components to monitor streams of + * {@link InputEvent}s without having to be the designated recipient for the event. + * + * For example, focus dispatched events would normally only go to the focused window on the + * targeted display, but an {@code InputMonitor} will also receive a copy of that event if they're + * registered to monitor that type of event on the targeted display. + * * @hide */ public final class InputMonitor implements Parcelable { diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 7c69cfde2b9e..1d721516a979 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -551,7 +551,7 @@ public class ScaleGestureDetector { (mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan < mPrevSpan)) || (!mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan > mPrevSpan)); final float spanDiff = (Math.abs(1 - (mCurrSpan / mPrevSpan)) * SCALE_FACTOR); - return mPrevSpan <= 0 ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff); + return mPrevSpan <= mSpanSlop ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff); } return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 51bcbbdb7e7d..c3a94655d7d5 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1377,59 +1377,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; - /** @hide */ - @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { - IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, - IMPORTANT_FOR_CONTENT_CAPTURE_YES, - IMPORTANT_FOR_CONTENT_CAPTURE_NO, - IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, - IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ContentCaptureImportance {} - - /** - * Automatically determine whether a view is important for content capture. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; - - /** - * The view is important for content capture, and its children (if any) will be traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; - - /** - * The view is not important for content capture, but its children (if any) will be traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; - - /** - * The view is important for content capture, but its children (if any) will not be traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; - - /** - * The view is not important for content capture, and its children (if any) will not be - * traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; - - /** * This view is enabled. Interpretation varies by subclass. * Use with ENABLED_MASK when calling setFlags. @@ -3402,55 +3349,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /* End of masks for mPrivateFlags3 */ - /* - * Masks for mPrivateFlags4, as generated by dumpFlags(): - * - * |-------|-------|-------|-------| - * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK - * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED - * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED - * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED - * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE - * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK - * |-------|-------|-------|-------| - */ - - /** - * Mask for obtaining the bits which specify how to determine - * whether a view is important for autofill. - * - * <p>NOTE: the important for content capture values were the first flags added and are set in - * the rightmost position, so we don't need to shift them - */ - private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = - IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES - | IMPORTANT_FOR_CONTENT_CAPTURE_NO - | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS - | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; - - /* - * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods - * should be called. - * - * The idea is to call notifyAppeared() after the view is layout and visible, then call - * notifyDisappeared() when it's gone (without known when it was removed from the parent). - */ - private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; - private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; - - /* - * Flags used to cache the value returned by isImportantForContentCapture while the view - * hierarchy is being traversed. - */ - private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; - private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; - - private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = - PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED - | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; - - /* End of masks for mPrivateFlags4 */ - /** @hide */ protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; /** @hide */ @@ -4074,8 +3972,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) int mPrivateFlags3; - private int mPrivateFlags4; - /** * This view's request for the visibility of the status bar. * @hide @@ -5808,11 +5704,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); } break; - case R.styleable.View_importantForContentCapture: - if (a.peekValue(attr) != null) { - setImportantForContentCapture(a.getInt(attr, - IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); - } case R.styleable.View_defaultFocusHighlightEnabled: if (a.peekValue(attr) != null) { setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); @@ -8532,62 +8423,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); } - /** - * Populates a {@link ViewStructure} for content capture. - * - * <p>This method is called after a view is that is eligible for content capture - * (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for - * the user, and the activity rendering the view is enabled for content capture) is laid out and - * is visible. - * - * <p>The populated structure is then passed to the service through - * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. - * - * <p><b>Note: </b>views that manage a virtual structure under this view must populate just - * the node representing this view and return right away, then asynchronously report (not - * necessarily in the UI thread) when the children nodes appear, disappear or have their text - * changed by calling - * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, - * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and - * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} - * respectively. The structure for the a child must be created using - * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the - * {@code autofillId} for a child can be obtained either through - * {@code childStructure.getAutofillId()} or - * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. - * - * <p>When the virtual view hierarchy represents a web page, you should also: - * - * <ul> - * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content - * capture events should be generate for that URL. - * <li>Create a new {@link ContentCaptureSession} child for every HTML element that - * renders a new URL (like an {@code IFRAME}) and use that session to notify events from - * that subtree. - * </ul> - * - * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: - * <ul> - * <li>{@link ViewStructure#setChildCount(int)} - * <li>{@link ViewStructure#addChildCount(int)} - * <li>{@link ViewStructure#getChildCount()} - * <li>{@link ViewStructure#newChild(int)} - * <li>{@link ViewStructure#asyncNewChild(int)} - * <li>{@link ViewStructure#asyncCommit()} - * <li>{@link ViewStructure#setWebDomain(String)} - * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} - * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} - * <li>{@link ViewStructure#setDataIsSensitive(boolean)} - * <li>{@link ViewStructure#setAlpha(float)} - * <li>{@link ViewStructure#setElevation(float)} - * <li>{@link ViewStructure#setTransformation(Matrix)} - * - * </ul> - */ - public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { - onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); - } - /** @hide */ protected void onProvideStructure(@NonNull ViewStructure structure, @ViewStructureType int viewFor, int flags) { @@ -9225,265 +9060,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Gets the mode for determining whether this view is important for content capture. - * - * <p>See {@link #setImportantForContentCapture(int)} and - * {@link #isImportantForContentCapture()} for more info about this mode. - * - * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to - * {@link #setImportantForContentCapture(int)}. - * - * @attr ref android.R.styleable#View_importantForContentCapture - */ - @ViewDebug.ExportedProperty(mapping = { - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, - to = "yesExcludeDescendants"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, - to = "noExcludeDescendants")}) - @InspectableProperty(enumMapping = { - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, - name = "yesExcludeDescendants"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, - name = "noExcludeDescendants"), - }) - public @ContentCaptureImportance int getImportantForContentCapture() { - // NOTE: the important for content capture values were the first flags added and are set in - // the rightmost position, so we don't need to shift them - return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; - } - - /** - * Sets the mode for determining whether this view is considered important for content capture. - * - * <p>The platform determines the importance for autofill automatically but you - * can use this method to customize the behavior. Typically, a view that provides text should - * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. - * - * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, - * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, - * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, - * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. - * - * @attr ref android.R.styleable#View_importantForContentCapture - */ - public void setImportantForContentCapture(@ContentCaptureImportance int mode) { - // Reset first - mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; - // Then set again - // NOTE: the important for content capture values were the first flags added and are set in - // the rightmost position, so we don't need to shift them - mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); - } - - /** - * Hints the Android System whether this view is considered important for content capture, based - * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics - * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. - * - * <p>See {@link ContentCaptureManager} for more info about content capture. - * - * @return whether the view is considered important for content capture. - * - * @see #setImportantForContentCapture(int) - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - */ - public final boolean isImportantForContentCapture() { - boolean isImportant; - if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { - isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; - return isImportant; - } - - isImportant = calculateIsImportantForContentCapture(); - - mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; - if (isImportant) { - mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; - } - mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; - return isImportant; - } - - /** - * Calculates whether the flag is important for content capture so it can be used by - * {@link #isImportantForContentCapture()} while the tree is traversed. - */ - private boolean calculateIsImportantForContentCapture() { - // Check parent mode to ensure we're important - ViewParent parent = mParent; - while (parent instanceof View) { - final int parentImportance = ((View) parent).getImportantForContentCapture(); - if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " - + "content capture because parent " + parent + "'s importance is " - + parentImportance); - } - return false; - } - parent = parent.getParent(); - } - - final int importance = getImportantForContentCapture(); - - // First, check the explicit states. - if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS - || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { - return true; - } - if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " - + "capture because its importance is " + importance); - } - return false; - } - - // Then use some heuristics to handle AUTO. - if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { - Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance - + " on view " + this); - return false; - } - - // View group is important if at least one children also is - if (this instanceof ViewGroup) { - final ViewGroup group = (ViewGroup) this; - for (int i = 0; i < group.getChildCount(); i++) { - final View child = group.getChildAt(i); - if (child.isImportantForContentCapture()) { - return true; - } - } - } - - // If the app developer explicitly set hints or autofill hintsfor it, it's important. - if (getAutofillHints() != null) { - return true; - } - - // Otherwise, assume it's not important... - return false; - } - - /** - * Helper used to notify the {@link ContentCaptureManager} when the view is removed or - * added, based on whether it's laid out and visible, and without knowing if the parent removed - * it from the view hierarchy. - * - * <p>This method is called from many places (visibility changed, view laid out, view attached - * or detached to/from window, etc...) and hence must contain the logic to call the manager, as - * described below: - * - * <ol> - * <li>It should only be called when content capture is enabled for the view. - * <li>It must call viewAppeared() before viewDisappeared() - * <li>viewAppearead() can only be called when the view is visible and laidout - * <li>It should not call the same event twice. - * </ol> - */ - private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { - AttachInfo ai = mAttachInfo; - // Skip it while the view is being laided out for the first time - if (ai != null && !ai.mReadyForContentCaptureUpdates) return; - - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, - "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName()); - } - try { - notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(appeared); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - } - - private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) { - AttachInfo ai = mAttachInfo; - - // First check if context has client, so it saves a service lookup when it doesn't - if (mContext.getContentCaptureOptions() == null) return; - - // Then check if it's enabled in the context... - final ContentCaptureManager ccm = ai != null ? ai.getContentCaptureManager(mContext) - : mContext.getSystemService(ContentCaptureManager.class); - if (ccm == null || !ccm.isContentCaptureEnabled()) return; - - // ... and finally at the view level - // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() - if (!isImportantForContentCapture()) return; - - ContentCaptureSession session = getContentCaptureSession(); - if (session == null) return; - - if (appeared) { - if (!isLaidOut() || getVisibility() != VISIBLE - || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" - + isLaidOut() + ", visibleToUser=" + isVisibleToUser() - + ", visible=" + (getVisibility() == VISIBLE) - + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) - + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); - } - return; - } - setNotifiedContentCaptureAppeared(); - - if (ai != null) { - ai.delayNotifyContentCaptureEvent(session, this, appeared); - } else { - if (DEBUG_CONTENT_CAPTURE) { - Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); - } - } - } else { - if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 - || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" - + isLaidOut() + ", visibleToUser=" + isVisibleToUser() - + ", visible=" + (getVisibility() == VISIBLE) - + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) - + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); - } - return; - } - mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; - mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; - - if (ai != null) { - ai.delayNotifyContentCaptureEvent(session, this, appeared); - } else { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); - } - } - } - } - - private void setNotifiedContentCaptureAppeared() { - mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; - mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; - } - - /** * Sets the (optional) {@link ContentCaptureSession} associated with this view. * * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to @@ -9739,68 +9315,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Dispatches the initial content capture events for a view structure. - * - * @hide - */ - public void dispatchInitialProvideContentCaptureStructure() { - AttachInfo ai = mAttachInfo; - if (ai == null) { - Log.w(CONTENT_CAPTURE_LOG_TAG, - "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); - return; - } - ContentCaptureManager ccm = ai.mContentCaptureManager; - if (ccm == null) { - Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " - + "no ContentCaptureManager for " + this); - return; - } - - // We must set it before checkign if the view itself is important, because it might - // initially not be (for example, if it's empty), although that might change later (for - // example, if important views are added) - ai.mReadyForContentCaptureUpdates = true; - - if (!isImportantForContentCapture()) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { - Log.d(CONTENT_CAPTURE_LOG_TAG, - "dispatchProvideContentCaptureStructure(): decorView is not important"); - } - return; - } - - ai.mContentCaptureManager = ccm; - - ContentCaptureSession session = getContentCaptureSession(); - if (session == null) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { - Log.d(CONTENT_CAPTURE_LOG_TAG, - "dispatchProvideContentCaptureStructure(): no session for " + this); - } - return; - } - - session.internalNotifyViewTreeEvent(/* started= */ true); - try { - dispatchProvideContentCaptureStructure(); - } finally { - session.internalNotifyViewTreeEvent(/* started= */ false); - } - } - - /** @hide */ - void dispatchProvideContentCaptureStructure() { - ContentCaptureSession session = getContentCaptureSession(); - if (session != null) { - ViewStructure structure = session.newViewStructure(this); - onProvideContentCaptureStructure(structure, /* flags= */ 0); - setNotifiedContentCaptureAppeared(); - session.notifyViewAppeared(structure); - } - } - - /** * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) * * Note: Called from the default {@link AccessibilityDelegate}. @@ -13753,7 +13267,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void dispatchStartTemporaryDetach() { mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); onStartTemporaryDetach(); } @@ -13780,7 +13293,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyFocusChangeToInputMethodManager(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } /** @@ -14372,8 +13884,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } } - - notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); } /** @@ -18069,7 +17579,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } // Reset content capture caches - mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; mCachedContentCaptureSession = null; if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) @@ -20079,7 +19588,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, needGlobalAttributesUpdate(false); notifyEnterOrExitForAutoFillIfNeeded(true); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @@ -20129,7 +19637,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** @@ -22442,8 +21949,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; notifyEnterOrExitForAutoFillIfNeeded(true); } - - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } private boolean hasParentWantsFocus() { @@ -28650,23 +28155,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, View mTooltipHost; /** - * The initial structure has been reported so the view is ready to report updates. - */ - boolean mReadyForContentCaptureUpdates; - - /** - * Map(keyed by session) of content capture events that need to be notified after the view - * hierarchy is traversed: value is either the view itself for appearead events, or its - * autofill id for disappeared. - */ - SparseArray<ArrayList<Object>> mContentCaptureEvents; - - /** - * Cached reference to the {@link ContentCaptureManager}. - */ - ContentCaptureManager mContentCaptureManager; - - /** * Creates a new set of attachment information with the specified * events handler and thread. * @@ -28684,31 +28172,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mRootCallbacks = effectPlayer; mTreeObserver = new ViewTreeObserver(context); } - - private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, - @NonNull View view, boolean appeared) { - if (mContentCaptureEvents == null) { - // Most of the time there will be just one session, so intial capacity is 1 - mContentCaptureEvents = new SparseArray<>(1); - } - int sessionId = session.getId(); - // TODO: life would be much easier if we provided a MultiMap implementation somwhere... - ArrayList<Object> events = mContentCaptureEvents.get(sessionId); - if (events == null) { - events = new ArrayList<>(); - mContentCaptureEvents.put(sessionId, events); - } - events.add(appeared ? view : view.getAutofillId()); - } - - @Nullable - ContentCaptureManager getContentCaptureManager(@NonNull Context context) { - if (mContentCaptureManager != null) { - return mContentCaptureManager; - } - mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); - return mContentCaptureManager; - } } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 937bd1b34e61..d362024ed525 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3606,7 +3606,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return; } - final ChildListForAutoFillOrContentCapture children = getChildrenForAutofill(flags); + final ChildListForAutofill children = getChildrenForAutofill(flags); final int childrenCount = children.size(); structure.setChildCount(childrenCount); for (int i = 0; i < childrenCount; i++) { @@ -3617,30 +3617,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager children.recycle(); } - /** @hide */ - @Override - public void dispatchProvideContentCaptureStructure() { - super.dispatchProvideContentCaptureStructure(); - - if (!isLaidOut()) return; - - final ChildListForAutoFillOrContentCapture children = getChildrenForContentCapture(); - final int childrenCount = children.size(); - for (int i = 0; i < childrenCount; i++) { - final View child = children.get(i); - child.dispatchProvideContentCaptureStructure(); - } - children.recycle(); - } - /** * Gets the children for autofill. Children for autofill are the first * level descendants that are important for autofill. The returned * child list object is pooled and the caller must recycle it once done. * @hide */ - private @NonNull ChildListForAutoFillOrContentCapture getChildrenForAutofill( + private @NonNull ChildListForAutofill getChildrenForAutofill( @AutofillFlags int flags) { - final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture + final ChildListForAutofill children = ChildListForAutofill .obtain(); populateChildrenForAutofill(children, flags); return children; @@ -3668,34 +3652,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - private @NonNull ChildListForAutoFillOrContentCapture getChildrenForContentCapture() { - final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture - .obtain(); - populateChildrenForContentCapture(children); - return children; - } - - /** @hide */ - private void populateChildrenForContentCapture(ArrayList<View> list) { - final int childrenCount = mChildrenCount; - if (childrenCount <= 0) { - return; - } - final ArrayList<View> preorderedList = buildOrderedChildList(); - final boolean customOrder = preorderedList == null - && isChildrenDrawingOrderEnabled(); - for (int i = 0; i < childrenCount; i++) { - final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); - final View child = (preorderedList == null) - ? mChildren[childIndex] : preorderedList.get(childIndex); - if (child.isImportantForContentCapture()) { - list.add(child); - } else if (child instanceof ViewGroup) { - ((ViewGroup) child).populateChildrenForContentCapture(list); - } - } - } - private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children, int childIndex) { final View child; @@ -8678,16 +8634,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Pooled class that to hold the children for autifill. */ - private static class ChildListForAutoFillOrContentCapture extends ArrayList<View> { + private static class ChildListForAutofill extends ArrayList<View> { private static final int MAX_POOL_SIZE = 32; - private static final Pools.SimplePool<ChildListForAutoFillOrContentCapture> sPool = + private static final Pools.SimplePool<ChildListForAutofill> sPool = new Pools.SimplePool<>(MAX_POOL_SIZE); - public static ChildListForAutoFillOrContentCapture obtain() { - ChildListForAutoFillOrContentCapture list = sPool.acquire(); + public static ChildListForAutofill obtain() { + ChildListForAutofill list = sPool.acquire(); if (list == null) { - list = new ChildListForAutoFillOrContentCapture(); + list = new ChildListForAutofill(); } return list; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f3b7ad5e557c..5ca70ba9a575 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -105,11 +105,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; -import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; -import android.view.contentcapture.ContentCaptureManager; -import android.view.contentcapture.ContentCaptureSession; -import android.view.contentcapture.MainContentCaptureSession; import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; @@ -224,21 +220,6 @@ public final class ViewRootImpl implements ViewParent, */ static final int MAX_TRACKBALL_DELAY = 250; - /** - * Initial value for {@link #mContentCaptureEnabled}. - */ - private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0; - - /** - * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}. - */ - private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1; - - /** - * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}. - */ - private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2; - @UnsupportedAppUsage static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>(); @@ -435,10 +416,6 @@ public final class ViewRootImpl implements ViewParent, boolean mLayoutRequested; boolean mFirst; - @Nullable - int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED; - boolean mPerformContentCapture; - boolean mReportNextDraw; boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; @@ -637,7 +614,6 @@ public final class ViewRootImpl implements ViewParent, mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); mFirst = true; // true for the first time the view is added - mPerformContentCapture = true; // also true for the first time the view is added mAdded = false; mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, context); @@ -2787,55 +2763,9 @@ public final class ViewRootImpl implements ViewParent, } } - if (mAttachInfo.mContentCaptureEvents != null) { - notifyContentCatpureEvents(); - } - mIsInTraversal = false; } - private void notifyContentCatpureEvents() { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents"); - try { - MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager - .getMainContentCaptureSession(); - for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) { - int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i); - mainSession.notifyViewTreeEvent(sessionId, /* started= */ true); - ArrayList<Object> events = mAttachInfo.mContentCaptureEvents - .valueAt(i); - for_each_event: for (int j = 0; j < events.size(); j++) { - Object event = events.get(j); - if (event instanceof AutofillId) { - mainSession.notifyViewDisappeared(sessionId, (AutofillId) event); - } else if (event instanceof View) { - View view = (View) event; - ContentCaptureSession session = view.getContentCaptureSession(); - if (session == null) { - Log.w(mTag, "no content capture session on view: " + view); - continue for_each_event; - } - int actualId = session.getId(); - if (actualId != sessionId) { - Log.w(mTag, "content capture session mismatch for view (" + view - + "): was " + sessionId + " before, it's " + actualId + " now"); - continue for_each_event; - } - ViewStructure structure = session.newViewStructure(view); - view.onProvideContentCaptureStructure(structure, /* flags= */ 0); - session.notifyViewAppeared(structure); - } else { - Log.w(mTag, "invalid content capture event: " + event); - } - } - mainSession.notifyViewTreeEvent(sessionId, /* started= */ false); - } - mAttachInfo.mContentCaptureEvents = null; - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - } - private void notifySurfaceDestroyed() { mSurfaceHolder.ungetCallbacks(); SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); @@ -2966,13 +2896,6 @@ public final class ViewRootImpl implements ViewParent, } } mFirstInputStage.onWindowFocusChanged(hasWindowFocus); - - // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus - // is lost, so we don't need to to force a flush - there might be other events such as - // text changes, but these should be flushed independently. - if (hasWindowFocus) { - handleContentCaptureFlush(); - } } private void fireAccessibilityFocusEventIfHasFocusedNode() { @@ -3539,86 +3462,6 @@ public final class ViewRootImpl implements ViewParent, pendingDrawFinished(); } } - if (mPerformContentCapture) { - performContentCaptureInitialReport(); - } - } - - /** - * Checks (and caches) if content capture is enabled for this context. - */ - private boolean isContentCaptureEnabled() { - switch (mContentCaptureEnabled) { - case CONTENT_CAPTURE_ENABLED_TRUE: - return true; - case CONTENT_CAPTURE_ENABLED_FALSE: - return false; - case CONTENT_CAPTURE_ENABLED_NOT_CHECKED: - final boolean reallyEnabled = isContentCaptureReallyEnabled(); - mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE - : CONTENT_CAPTURE_ENABLED_FALSE; - return reallyEnabled; - default: - Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled); - return false; - } - - } - - /** - * Checks (without caching) if content capture is enabled for this context. - */ - private boolean isContentCaptureReallyEnabled() { - // First check if context supports it, so it saves a service lookup when it doesn't - if (mContext.getContentCaptureOptions() == null) return false; - - final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext); - // Then check if it's enabled in the contex itself. - if (ccm == null || !ccm.isContentCaptureEnabled()) return false; - - return true; - } - - private void performContentCaptureInitialReport() { - mPerformContentCapture = false; // One-time offer! - final View rootView = mView; - if (DEBUG_CONTENT_CAPTURE) { - Log.v(mTag, "performContentCaptureInitialReport() on " + rootView); - } - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for " - + getClass().getSimpleName()); - } - try { - if (!isContentCaptureEnabled()) return; - - // Content capture is a go! - rootView.dispatchInitialProvideContentCaptureStructure(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - } - - private void handleContentCaptureFlush() { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(mTag, "handleContentCaptureFlush()"); - } - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for " - + getClass().getSimpleName()); - } - try { - if (!isContentCaptureEnabled()) return; - - final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager; - if (ccm == null) { - Log.w(TAG, "No ContentCapture on AttachInfo"); - return; - } - ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } } private boolean draw(boolean fullRedrawNeeded) { diff --git a/core/java/android/view/autofill/AutofillManagerInternal.java b/core/java/android/view/autofill/AutofillManagerInternal.java index 3de1a03d98e5..a07d46d77258 100644 --- a/core/java/android/view/autofill/AutofillManagerInternal.java +++ b/core/java/android/view/autofill/AutofillManagerInternal.java @@ -45,4 +45,12 @@ public abstract class AutofillManagerInternal { @Nullable public abstract AutofillOptions getAutofillOptions(@NonNull String packageName, long versionCode, @UserIdInt int userId); + + /** + * Checks whether the given {@code uid} owns the + * {@link android.service.autofill.augmented.AugmentedAutofillService} implementation associated + * with the given {@code userId}. + */ + public abstract boolean isAugmentedAutofillServiceForUser(@NonNull int callingUid, + @UserIdInt int userId); } diff --git a/core/java/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java index 6f9d4d30909f..54ebf55a0063 100644 --- a/core/java/android/view/contentcapture/ContentCaptureCondition.java +++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java @@ -35,7 +35,8 @@ import java.lang.annotation.RetentionPolicy; public final class ContentCaptureCondition implements Parcelable { /** - * When set, package should use the {@link LocusId#getId()} as a regular expression. + * When set, package should use the {@link LocusId#getId()} as a regular expression (using the + * {@link java.util.regex.Pattern} format). */ public static final int FLAG_IS_REGEX = 0x2; diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 253935680cb8..7a6e2adfcaa4 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -191,8 +191,8 @@ import java.util.Set; * * <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws * the HTML using {@link Canvas} or native libraries in a different render process), then the view - * is also responsible to notify the session when the virtual elements appear and disappear - see - * {@link View#onProvideContentCaptureStructure(ViewStructure, int)} for more info. + * is also responsible to notify the session when the virtual elements appear and disappear - + * see {@link ContentCaptureSession#newViewStructure(View)} for more info. */ @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE) public final class ContentCaptureManager { @@ -578,16 +578,15 @@ public final class ContentCaptureManager { } /** - * Called by the app to request the content capture service to remove user-data associated with - * some context. + * Called by the app to remove content capture data associated with some context. * - * @param request object specifying what user data should be removed. + * @param request object specifying what data should be removed. */ - public void removeUserData(@NonNull UserDataRemovalRequest request) { + public void removeData(@NonNull DataRemovalRequest request) { Preconditions.checkNotNull(request); try { - mService.removeUserData(request); + mService.removeData(request); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 7761038f8af1..17a1fb405321 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -356,10 +356,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Notifies the Content Capture Service that a node has been added to the view structure. * - * <p>Typically called "manually" by views that handle their own virtual view hierarchy, or - * automatically by the Android System for views that return {@code true} on - * {@link View#onProvideContentCaptureStructure(ViewStructure, int)}. - * * @param node node that has been added. */ public final void notifyViewAppeared(@NonNull ViewStructure node) { @@ -378,9 +374,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Notifies the Content Capture Service that a node has been removed from the view structure. * - * <p>Typically called "manually" by views that handle their own virtual view hierarchy, or - * automatically by the Android System for standard views. - * * @param id id of the node that has been removed. */ public final void notifyViewDisappeared(@NonNull AutofillId id) { @@ -441,7 +434,46 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Creates a {@link ViewStructure} for a "standard" view. * - * @hide + * <p>This method should be called after a visible view is laid out; the view then must populate + * the structure and pass it to {@link #notifyViewAppeared(ViewStructure)}. + * + * <b>Note: </b>views that manage a virtual structure under this view must populate just the + * node representing this view and return right away, then asynchronously report (not + * necessarily in the UI thread) when the children nodes appear, disappear or have their text + * changed by calling {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, + * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and + * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} respectively. + * The structure for the a child must be created using + * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the + * {@code autofillId} for a child can be obtained either through + * {@code childStructure.getAutofillId()} or + * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. + * + * <p>When the virtual view hierarchy represents a web page, you should also: + * + * <ul> + * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content capture + * events should be generate for that URL. + * <li>Create a new {@link ContentCaptureSession} child for every HTML element that renders a + * new URL (like an {@code IFRAME}) and use that session to notify events from that subtree. + * </ul> + * + * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: + * <ul> + * <li>{@link ViewStructure#setChildCount(int)} + * <li>{@link ViewStructure#addChildCount(int)} + * <li>{@link ViewStructure#getChildCount()} + * <li>{@link ViewStructure#newChild(int)} + * <li>{@link ViewStructure#asyncNewChild(int)} + * <li>{@link ViewStructure#asyncCommit()} + * <li>{@link ViewStructure#setWebDomain(String)} + * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} + * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} + * <li>{@link ViewStructure#setDataIsSensitive(boolean)} + * <li>{@link ViewStructure#setAlpha(float)} + * <li>{@link ViewStructure#setElevation(float)} + * <li>{@link ViewStructure#setTransformation(android.graphics.Matrix)} + * </ul> */ @NonNull public final ViewStructure newViewStructure(@NonNull View view) { diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.aidl b/core/java/android/view/contentcapture/DataRemovalRequest.aidl index fbe47e08ea7c..c89d222d159f 100644 --- a/core/java/android/view/contentcapture/UserDataRemovalRequest.aidl +++ b/core/java/android/view/contentcapture/DataRemovalRequest.aidl @@ -16,4 +16,4 @@ package android.view.contentcapture; -parcelable UserDataRemovalRequest; +parcelable DataRemovalRequest; diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.java b/core/java/android/view/contentcapture/DataRemovalRequest.java index 3e1e4abaa84c..3792846bea71 100644 --- a/core/java/android/view/contentcapture/UserDataRemovalRequest.java +++ b/core/java/android/view/contentcapture/DataRemovalRequest.java @@ -31,14 +31,12 @@ import java.util.ArrayList; import java.util.List; /** - * Class used by apps to request the Content Capture service to remove user-data associated with - * some context. + * Class used by apps to remove content capture data associated with {@link LocusId LocusIds}. */ -public final class UserDataRemovalRequest implements Parcelable { +public final class DataRemovalRequest implements Parcelable { /** - * When set, service should use the {@link LocusId#getId()} as prefix for the data to be - * removed. + * When set, the {@link LocusId#getId()} is the prefix for the data to be removed. */ public static final int FLAG_IS_PREFIX = 0x1; @@ -54,7 +52,7 @@ public final class UserDataRemovalRequest implements Parcelable { private final boolean mForEverything; private ArrayList<LocusIdRequest> mLocusIdRequests; - private UserDataRemovalRequest(@NonNull Builder builder) { + private DataRemovalRequest(@NonNull Builder builder) { mPackageName = ActivityThread.currentActivityThread().getApplication().getPackageName(); mForEverything = builder.mForEverything; if (builder.mLocusIds != null) { @@ -67,7 +65,7 @@ public final class UserDataRemovalRequest implements Parcelable { } } - private UserDataRemovalRequest(@NonNull Parcel parcel) { + private DataRemovalRequest(@NonNull Parcel parcel) { mPackageName = parcel.readString(); mForEverything = parcel.readBoolean(); if (!mForEverything) { @@ -89,7 +87,7 @@ public final class UserDataRemovalRequest implements Parcelable { } /** - * Checks if app is requesting to remove all user data associated with its package. + * Checks if app is requesting to remove content capture data associated with its package. */ public boolean isForEverything() { return mForEverything; @@ -104,7 +102,7 @@ public final class UserDataRemovalRequest implements Parcelable { } /** - * Builder for {@link UserDataRemovalRequest} objects. + * Builder for {@link DataRemovalRequest} objects. */ public static final class Builder { @@ -115,7 +113,7 @@ public final class UserDataRemovalRequest implements Parcelable { private boolean mDestroyed; /** - * Requests servive to remove all user data associated with the app's package. + * Requests to remove all content capture data associated with the app's package. * * @return this builder */ @@ -132,7 +130,7 @@ public final class UserDataRemovalRequest implements Parcelable { * Request service to remove data associated with a given {@link LocusId}. * * @param locusId the {@link LocusId} being requested to be removed. - * @param flags either {@link UserDataRemovalRequest#FLAG_IS_PREFIX} or {@code 0} + * @param flags either {@link DataRemovalRequest#FLAG_IS_PREFIX} or {@code 0} * * @return this builder */ @@ -154,17 +152,17 @@ public final class UserDataRemovalRequest implements Parcelable { } /** - * Builds the {@link UserDataRemovalRequest}. + * Builds the {@link DataRemovalRequest}. */ @NonNull - public UserDataRemovalRequest build() { + public DataRemovalRequest build() { throwIfDestroyed(); Preconditions.checkState(mForEverything || mLocusIds != null, "must call either #forEverything() or add one #addLocusId()"); mDestroyed = true; - return new UserDataRemovalRequest(this); + return new DataRemovalRequest(this); } private void throwIfDestroyed() { @@ -192,19 +190,19 @@ public final class UserDataRemovalRequest implements Parcelable { } } - public static final @android.annotation.NonNull Parcelable.Creator<UserDataRemovalRequest> CREATOR = - new Parcelable.Creator<UserDataRemovalRequest>() { + public static final @android.annotation.NonNull Parcelable.Creator<DataRemovalRequest> CREATOR = + new Parcelable.Creator<DataRemovalRequest>() { @Override @NonNull - public UserDataRemovalRequest createFromParcel(Parcel parcel) { - return new UserDataRemovalRequest(parcel); + public DataRemovalRequest createFromParcel(Parcel parcel) { + return new DataRemovalRequest(parcel); } @Override @NonNull - public UserDataRemovalRequest[] newArray(int size) { - return new UserDataRemovalRequest[size]; + public DataRemovalRequest[] newArray(int size) { + return new DataRemovalRequest[size]; } }; @@ -231,7 +229,7 @@ public final class UserDataRemovalRequest implements Parcelable { /** * Gets the flags associates with request. * - * @return either {@link UserDataRemovalRequest#FLAG_IS_PREFIX} or {@code 0}. + * @return either {@link DataRemovalRequest#FLAG_IS_PREFIX} or {@code 0}. */ @NonNull public @Flags int getFlags() { diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl index 7335073c59e0..ced941744387 100644 --- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl +++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl @@ -19,7 +19,7 @@ package android.view.contentcapture; import android.content.ComponentName; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureEvent; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import android.os.IBinder; import com.android.internal.os.IResultReceiver; @@ -59,9 +59,9 @@ oneway interface IContentCaptureManager { void getServiceComponentName(in IResultReceiver result); /** - * Requests the removal of user data for the calling user. + * Requests the removal of content capture data for the calling user. */ - void removeUserData(in UserDataRemovalRequest request); + void removeData(in DataRemovalRequest request); /** * Returns whether the content capture feature is enabled for the calling user. diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java index b408129231e7..f2fa67d58839 100644 --- a/core/java/android/view/textclassifier/ConversationActions.java +++ b/core/java/android/view/textclassifier/ConversationActions.java @@ -316,16 +316,20 @@ public final class ConversationActions implements Parcelable { private final List<String> mHints; @Nullable private String mCallingPackageName; + @NonNull + private Bundle mExtras; private Request( @NonNull List<Message> conversation, @NonNull TextClassifier.EntityConfig typeConfig, int maxSuggestions, - @Nullable @Hint List<String> hints) { + @Nullable @Hint List<String> hints, + @NonNull Bundle extras) { mConversation = Preconditions.checkNotNull(conversation); mTypeConfig = Preconditions.checkNotNull(typeConfig); mMaxSuggestions = maxSuggestions; mHints = hints; + mExtras = extras; } private static Request readFromParcel(Parcel in) { @@ -336,12 +340,13 @@ public final class ConversationActions implements Parcelable { List<String> hints = new ArrayList<>(); in.readStringList(hints); String callingPackageName = in.readString(); - + Bundle extras = in.readBundle(); Request request = new Request( conversation, typeConfig, maxSuggestions, - hints); + hints, + extras); request.setCallingPackageName(callingPackageName); return request; } @@ -353,6 +358,7 @@ public final class ConversationActions implements Parcelable { parcel.writeInt(mMaxSuggestions); parcel.writeStringList(mHints); parcel.writeString(mCallingPackageName); + parcel.writeBundle(mExtras); } @Override @@ -421,6 +427,16 @@ public final class ConversationActions implements Parcelable { return mCallingPackageName; } + /** + * Returns the extended data related to this request. + * + * <p><b>NOTE: </b>Do not modify this bundle. + */ + @NonNull + public Bundle getExtras() { + return mExtras; + } + /** Builder object to construct the {@link Request} object. */ public static final class Builder { @NonNull @@ -431,6 +447,8 @@ public final class ConversationActions implements Parcelable { @Nullable @Hint private List<String> mHints; + @Nullable + private Bundle mExtras; /** * Constructs a builder. @@ -469,6 +487,13 @@ public final class ConversationActions implements Parcelable { return this; } + /** Sets a set of extended data to the request. */ + @NonNull + public Builder setExtras(@Nullable Bundle bundle) { + mExtras = bundle; + return this; + } + /** Builds the {@link Request} object. */ @NonNull public Request build() { @@ -480,7 +505,8 @@ public final class ConversationActions implements Parcelable { mMaxSuggestions, mHints == null ? Collections.emptyList() - : Collections.unmodifiableList(mHints)); + : Collections.unmodifiableList(mHints), + mExtras == null ? Bundle.EMPTY : mExtras); } } } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 26dba45666fc..137b67c6e63e 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -413,9 +413,6 @@ public class WebView extends AbsoluteLayout if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) { setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES); } - if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { - setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES); - } if (context == null) { throw new IllegalArgumentException("Invalid context argument"); @@ -2799,11 +2796,6 @@ public class WebView extends AbsoluteLayout } @Override - public void onProvideContentCaptureStructure(ViewStructure structure, int flags) { - mProvider.getViewDelegate().onProvideContentCaptureStructure(structure, flags); - } - - @Override public void autofill(SparseArray<AutofillValue>values) { mProvider.getViewDelegate().autofill(values); } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index c55f7d654548..c3bb9a0201d0 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -1318,8 +1318,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { @ViewStructureType int viewFor, int flags) { super.onProvideStructure(structure, viewFor, flags); - if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { final Adapter adapter = getAdapter(); if (adapter == null) return; diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 37bed6538a26..4c32f03f6cb3 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -21,6 +21,7 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.res.ResourceId; import android.content.res.TypedArray; import android.graphics.Rect; import android.os.Build; @@ -1991,7 +1992,7 @@ public class RelativeLayout extends ViewGroup { // dependencies for a specific set of rules for (int j = 0; j < rulesCount; j++) { final int rule = rules[rulesFilter[j]]; - if (rule > 0) { + if (ResourceId.isValid(rule)) { // The node this node depends on final Node dependency = keyNodes.get(rule); // Skip unknowns and self dependencies diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index a961783dab7c..618b05f8cb00 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -161,8 +161,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AnimationUtils; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; -import android.view.contentcapture.ContentCaptureManager; -import android.view.contentcapture.ContentCaptureSession; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CorrectionInfo; @@ -978,9 +976,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) { setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES); } - if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { - setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES); - } setTextInternal(""); @@ -10520,8 +10515,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Notify managers (such as {@link AutofillManager} and {@link ContentCaptureManager}) that are - * interested on text changes. + * Notify managers (such as {@link AutofillManager}) that are interested in text changes. */ private void notifyListeningManagersAfterTextChanged() { @@ -10537,22 +10531,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener afm.notifyValueChanged(TextView.this); } } - - // TODO(b/121045053): should use a flag / boolean to keep status of SHOWN / HIDDEN instead - // of using isLaidout(), so it's not called in cases where it's laid out but a - // notifyAppeared was not sent. - - // ContentCapture - if (isLaidOut() && isImportantForContentCapture() && isTextEditable()) { - final ContentCaptureManager cm = mContext.getSystemService(ContentCaptureManager.class); - if (cm != null && cm.isContentCaptureEnabled()) { - final ContentCaptureSession session = getContentCaptureSession(); - if (session != null) { - // TODO(b/111276913): pass flags when edited by user / add CTS test - session.notifyViewTextChanged(getAutofillId(), getText()); - } - } - } } private boolean isAutofillable() { @@ -11386,8 +11364,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod() || isPasswordInputType(getInputType()); - if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { structure.setDataIsSensitive(!mTextSetFromXmlOrResourceId); } @@ -11403,12 +11380,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { if (mLayout == null) { - if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { - Log.w(LOG_TAG, "onProvideContentCaptureStructure(): calling assumeLayout()"); - } assumeLayout(); } Layout layout = mLayout; @@ -11496,8 +11469,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (viewFor == VIEW_STRUCTURE_FOR_ASSIST - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { // Extract style information that applies to the TextView as a whole. int style = 0; int typefaceStyle = getTypefaceStyle(); @@ -11525,8 +11497,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener structure.setTextStyle(getTextSize(), getCurrentTextColor(), AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style); } - if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { structure.setMinTextEms(getMinEms()); structure.setMaxTextEms(getMaxEms()); int maxLength = -1; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index bfdbf4c1ec23..ed851f86889d 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -24,6 +24,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; import android.app.prediction.AppPredictionContext; @@ -83,6 +84,7 @@ import android.service.chooser.ChooserTarget; import android.service.chooser.ChooserTargetService; import android.service.chooser.IChooserTargetResult; import android.service.chooser.IChooserTargetService; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.AttributeSet; import android.util.HashedStringCache; @@ -131,6 +133,7 @@ import java.util.List; public class ChooserActivity extends ResolverActivity { private static final String TAG = "ChooserActivity"; + /** * Boolean extra to change the following behavior: Normally, ChooserActivity finishes itself * in onStop when launched in a new task. If this extra is set to true, we do not finish @@ -141,7 +144,6 @@ public class ChooserActivity extends ResolverActivity { private static final boolean DEBUG = false; - /** * If {@link #USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS} and this is set to true, * {@link AppPredictionManager} will be queried for direct share targets. @@ -433,18 +435,8 @@ public class ChooserActivity extends ResolverActivity { .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType()) .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost)); - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { - final IntentFilter filter = getTargetIntentFilter(); - Bundle extras = new Bundle(); - extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); - AppPredictionManager appPredictionManager = - getSystemService(AppPredictionManager.class); - mAppPredictor = appPredictionManager.createAppPredictionSession( - new AppPredictionContext.Builder(this) - .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) - .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) - .setExtras(extras) - .build()); + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); + if (appPredictor != null) { mAppPredictorCallback = resultList -> { if (isFinishing() || isDestroyed()) { return; @@ -467,8 +459,10 @@ public class ChooserActivity extends ResolverActivity { appTarget.getPackageName(), appTarget.getClassName()))); } sendShareShortcutInfoList(shareShortcutInfos, driList); + sendShortcutManagerShareTargetResultCompleted(); }; - mAppPredictor.registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback); + appPredictor + .registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback); } mChooserRowLayer = getResources().getDrawable(R.drawable.chooser_row_layer_list, null); @@ -872,7 +866,7 @@ public class ChooserActivity extends ResolverActivity { mChooserHandler.removeMessages(LIST_VIEW_UPDATE_MESSAGE); mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT); mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT); - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { + if (mAppPredictor != null) { mAppPredictor.unregisterPredictionUpdates(mAppPredictorCallback); mAppPredictor.destroy(); } @@ -1205,10 +1199,12 @@ public class ChooserActivity extends ResolverActivity { } private void queryDirectShareTargets(ChooserListAdapter adapter) { - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { - mAppPredictor.requestPredictionUpdate(); + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); + if (appPredictor != null) { + appPredictor.requestPredictionUpdate(); return; } + // Default to just querying ShortcutManager if AppPredictor not present. final IntentFilter filter = getTargetIntentFilter(); if (filter == null) { return; @@ -1248,12 +1244,16 @@ public class ChooserActivity extends ResolverActivity { } if (resultMessageSent) { - final Message msg = Message.obtain(); - msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED; - mChooserHandler.sendMessage(msg); + sendShortcutManagerShareTargetResultCompleted(); } } + private void sendShortcutManagerShareTargetResultCompleted() { + final Message msg = Message.obtain(); + msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED; + mChooserHandler.sendMessage(msg); + } + private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); Bundle extras = new Bundle(); @@ -1309,9 +1309,7 @@ public class ChooserActivity extends ResolverActivity { void updateModelAndChooserCounts(TargetInfo info) { if (info != null) { - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { - sendClickToAppPredictor(info); - } + sendClickToAppPredictor(info); final ResolveInfo ri = info.getResolveInfo(); Intent targetIntent = getTargetIntent(); if (ri != null && ri.activityInfo != null && targetIntent != null) { @@ -1332,6 +1330,10 @@ public class ChooserActivity extends ResolverActivity { } private void sendClickToAppPredictor(TargetInfo targetInfo) { + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); + if (appPredictor == null) { + return; + } if (!(targetInfo instanceof ChooserTargetInfo)) { return; } @@ -1345,15 +1347,44 @@ public class ChooserActivity extends ResolverActivity { if (shortcutId == null) { return; } - mAppPredictor.notifyAppTargetEvent( + appPredictor.notifyAppTargetEvent( new AppTargetEvent.Builder( - new AppTarget.Builder(new AppTargetId(shortcutId)) - .setTarget(componentName.getPackageName(), getUser()) + // TODO(b/124404997) Send full shortcut info, not just Id with AppTargetId. + new AppTarget.Builder(new AppTargetId(shortcutId), + componentName.getPackageName(), getUser()) .setClassName(componentName.getClassName()) .build(), - AppTargetEvent.ACTION_LAUNCH - ).setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE) - .build()); + AppTargetEvent.ACTION_LAUNCH) + .setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE) + .build()); + } + + @Nullable + private AppPredictor getAppPredictor() { + if (mAppPredictor == null + && getPackageManager().getAppPredictionServicePackageName() != null) { + final IntentFilter filter = getTargetIntentFilter(); + Bundle extras = new Bundle(); + extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); + AppPredictionContext appPredictionContext = new AppPredictionContext.Builder(this) + .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) + .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) + .setExtras(extras) + .build(); + AppPredictionManager appPredictionManager + = getSystemService(AppPredictionManager.class); + mAppPredictor = appPredictionManager.createAppPredictionSession(appPredictionContext); + } + return mAppPredictor; + } + + /** + * This will return an app predictor if it is enabled for direct share sorting + * and if one exists. Otherwise, it returns null. + */ + @Nullable + private AppPredictor getAppPredictorForDirectShareIfEnabled() { + return USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS ? getAppPredictor() : null; } void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) { @@ -1427,11 +1458,9 @@ public class ChooserActivity extends ResolverActivity { } private void updateAlphabeticalList() { - if (getDisplayList().size() > MAX_RANKED_TARGETS) { - mSortedList.clear(); - mSortedList.addAll(getDisplayList()); - Collections.sort(mSortedList, new AzInfoComparator(ChooserActivity.this)); - } + mSortedList.clear(); + mSortedList.addAll(getDisplayList()); + Collections.sort(mSortedList, new AzInfoComparator(ChooserActivity.this)); } /** @@ -1518,6 +1547,29 @@ public class ChooserActivity extends ResolverActivity { float getModifiedScore(); ChooserTarget getChooserTarget(); + + /** + * Do not label as 'equals', since this doesn't quite work + * as intended with java 8. + */ + default boolean isSimilar(ChooserTargetInfo other) { + if (other == null) return false; + + ChooserTarget ct1 = getChooserTarget(); + ChooserTarget ct2 = other.getChooserTarget(); + + // If either is null, there is not enough info to make an informed decision + // about equality, so just exit + if (ct1 == null || ct2 == null) return false; + + if (ct1.getComponentName().equals(ct2.getComponentName()) + && TextUtils.equals(getDisplayLabel(), other.getDisplayLabel()) + && TextUtils.equals(getExtendedInfo(), other.getExtendedInfo())) { + return true; + } + + return false; + } } /** @@ -1596,6 +1648,7 @@ public class ChooserActivity extends ResolverActivity { private final DisplayResolveInfo mSourceInfo; private final ResolveInfo mBackupResolveInfo; private final ChooserTarget mChooserTarget; + private final String mDisplayLabel; private Drawable mBadgeIcon = null; private CharSequence mBadgeContentDescription; private Drawable mDisplayIcon; @@ -1633,6 +1686,8 @@ public class ChooserActivity extends ResolverActivity { mFillInIntent = null; mFillInFlags = 0; + + mDisplayLabel = sanitizeDisplayLabel(chooserTarget.getTitle()); } private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) { @@ -1645,6 +1700,14 @@ public class ChooserActivity extends ResolverActivity { mFillInIntent = fillInIntent; mFillInFlags = flags; mModifiedScore = other.mModifiedScore; + + mDisplayLabel = sanitizeDisplayLabel(mChooserTarget.getTitle()); + } + + private String sanitizeDisplayLabel(CharSequence label) { + SpannableStringBuilder sb = new SpannableStringBuilder(label); + sb.clearSpans(); + return sb.toString(); } public boolean isSuspended() { @@ -1783,7 +1846,7 @@ public class ChooserActivity extends ResolverActivity { @Override public CharSequence getDisplayLabel() { - return mChooserTarget.getTitle(); + return mDisplayLabel; } @Override @@ -2016,7 +2079,8 @@ public class ChooserActivity extends ResolverActivity { } } - if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) { + if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS + || USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { if (DEBUG) { Log.d(TAG, "querying direct share targets from ShortcutManager"); } @@ -2047,12 +2111,13 @@ public class ChooserActivity extends ResolverActivity { @Override public int getUnfilteredCount() { int appTargets = super.getUnfilteredCount(); - if (appTargets > MAX_RANKED_TARGETS) { - appTargets = appTargets + MAX_RANKED_TARGETS; + if (appTargets > getMaxRankedTargets()) { + appTargets = appTargets + getMaxRankedTargets(); } return appTargets + getSelectableServiceTargetCount() + getCallerTargetCount(); } + public int getCallerTargetCount() { return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS); } @@ -2080,14 +2145,17 @@ public class ChooserActivity extends ResolverActivity { int getAlphaTargetCount() { int standardCount = super.getCount(); - return standardCount > MAX_RANKED_TARGETS ? standardCount : 0; + return standardCount > getMaxRankedTargets() ? standardCount : 0; } int getRankedTargetCount() { - int spacesAvailable = MAX_RANKED_TARGETS - getCallerTargetCount(); + int spacesAvailable = getMaxRankedTargets() - getCallerTargetCount(); return Math.min(spacesAvailable, super.getCount()); } + private int getMaxRankedTargets() { + return mChooserRowAdapter == null ? 4 : mChooserRowAdapter.getMaxTargetsPerRow(); + } public int getPositionTargetType(int position) { int offset = 0; @@ -2196,8 +2264,6 @@ public class ChooserActivity extends ResolverActivity { final float baseScore = getBaseScore(origTarget, isShortcutResult); Collections.sort(targets, mBaseTargetComparator); - - float lastScore = 0; boolean shouldNotify = false; for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) { @@ -2240,7 +2306,7 @@ public class ChooserActivity extends ResolverActivity { return CALLER_TARGET_SCORE_BOOST; } - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { + if (getAppPredictorForDirectShareIfEnabled() != null) { return SHORTCUT_TARGET_SCORE_BOOST; } @@ -2272,8 +2338,15 @@ public class ChooserActivity extends ResolverActivity { return false; } - final float newScore = chooserTargetInfo.getModifiedScore(); + // Check for duplicates and abort if found + for (ChooserTargetInfo otherTargetInfo : mServiceTargets) { + if (chooserTargetInfo.isSimilar(otherTargetInfo)) { + return false; + } + } + int currentSize = mServiceTargets.size(); + final float newScore = chooserTargetInfo.getModifiedScore(); for (int i = 0; i < Math.min(currentSize, MAX_SERVICE_TARGETS); i++) { final ChooserTargetInfo serviceTarget = mServiceTargets.get(i); if (serviceTarget == null) { @@ -2360,15 +2433,11 @@ public class ChooserActivity extends ResolverActivity { * @return true if the view width has changed */ public boolean calculateChooserTargetWidth(int width) { - int targetMinWidth = getResources().getDimensionPixelSize( - R.dimen.chooser_target_width); - if (width == 0) { return false; } - int targetWidth = width / getMaxTargetsPerRow(); - int newWidth = Math.max(targetWidth, targetMinWidth); + int newWidth = width / getMaxTargetsPerRow(); if (newWidth != mChooserTargetWidth) { mChooserTargetWidth = newWidth; return true; diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java index a85485d3969b..2484109f8520 100644 --- a/core/java/com/android/internal/app/SimpleIconFactory.java +++ b/core/java/com/android/internal/app/SimpleIconFactory.java @@ -34,6 +34,8 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.AdaptiveIconDrawable; @@ -56,7 +58,7 @@ import java.nio.ByteBuffer; /** * @deprecated Use the Launcher3 Iconloaderlib at packages/apps/Launcher3/iconloaderlib. This class * is a temporary fork of Iconloader. It combines all necessary methods to render app icons that are - * possibly badged. It is intended to be used only by Sharesheet for the Q release. + * possibly badged. It is intended to be used only by Sharesheet for the Q release with custom code. */ @Deprecated public class SimpleIconFactory { @@ -202,6 +204,7 @@ public class SimpleIconFactory { /** * Creates bitmap using the source drawable and flattened pre-rendered app icon. * The bitmap is visually normalized with other icons and has enough spacing to add shadow. + * This is custom functionality added to Iconloaderlib that will need to be ported. * * @param icon source of the icon associated with a user that has no badge * @param renderedAppIcon pre-rendered app icon to use as a badge, likely the output @@ -212,34 +215,70 @@ public class SimpleIconFactory { */ @Deprecated Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) { - // Flatten the passed in icon - float [] scale = new float[1]; - // If no icon is provided use the system default if (icon == null) { icon = getFullResDefaultActivityIcon(mFillResIconDpi); } - icon = normalizeAndWrapToAdaptiveIcon(icon, null, scale); - Bitmap bitmap = createIconBitmap(icon, scale[0]); - if (icon instanceof AdaptiveIconDrawable) { - mCanvas.setBitmap(bitmap); - recreateIcon(Bitmap.createBitmap(bitmap), mCanvas); - mCanvas.setBitmap(null); + + // Direct share icons cannot be adaptive, most will arrive as bitmaps. To get reliable + // presentation, force all DS icons to be circular. Scale DS image so it completely fills. + int w = icon.getIntrinsicWidth(); + int h = icon.getIntrinsicHeight(); + float scale = 1; + if (h > w && w > 0) { + scale = (float) h / w; + } else if (w > h && h > 0) { + scale = (float) w / h; } + Bitmap bitmap = createIconBitmap(icon, scale); + bitmap = maskBitmapToCircle(bitmap); + icon = new BitmapDrawable(mContext.getResources(), bitmap); - // Now scale down and apply the badge to the bottom right corner of the flattened icon - renderedAppIcon = Bitmap.createScaledBitmap(renderedAppIcon, mBadgeBitmapSize, - mBadgeBitmapSize, false); + // We now have a circular masked and scaled icon, inset and apply shadow + scale = getScale(icon, null); + bitmap = createIconBitmap(icon, scale); - // Paint the provided badge on top of the flattened icon mCanvas.setBitmap(bitmap); - mCanvas.drawBitmap(renderedAppIcon, mIconBitmapSize - mBadgeBitmapSize, - mIconBitmapSize - mBadgeBitmapSize, null); + recreateIcon(Bitmap.createBitmap(bitmap), mCanvas); + + if (renderedAppIcon != null) { + // Now scale down and apply the badge to the bottom right corner of the flattened icon + renderedAppIcon = Bitmap.createScaledBitmap(renderedAppIcon, mBadgeBitmapSize, + mBadgeBitmapSize, false); + + // Paint the provided badge on top of the flattened icon + mCanvas.drawBitmap(renderedAppIcon, mIconBitmapSize - mBadgeBitmapSize, + mIconBitmapSize - mBadgeBitmapSize, null); + } + mCanvas.setBitmap(null); return bitmap; } + private Bitmap maskBitmapToCircle(Bitmap bitmap) { + final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), + bitmap.getHeight(), Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(output); + final Paint paint = new Paint(); + paint.setAntiAlias(true); + + // Draw mask + paint.setColor(0xffffffff); + canvas.drawARGB(0, 0, 0, 0); + canvas.drawCircle(bitmap.getWidth() / 2f, + bitmap.getHeight() / 2f, + bitmap.getWidth() / 2f - 1 /* -1 to avoid circles with flat sides */, + paint); + + // Draw masked bitmap + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + canvas.drawBitmap(bitmap, rect, rect, paint); + + return output; + } + private static Drawable getFullResDefaultActivityIcon(int iconDpi) { return Resources.getSystem().getDrawableForDensity(android.R.mipmap.sym_def_app_icon, iconDpi); diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index 18c4b467dfba..a7244a744abf 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -332,33 +332,11 @@ public abstract class FileSystemProvider extends DocumentsProvider { } private void moveInMediaStore(@Nullable File oldVisibleFile, @Nullable File newVisibleFile) { - // visibleFolders are null if we're moving a document in external thumb drive or SD card. - // - // They should be all null or not null at the same time. File#renameTo() doesn't work across - // volumes so an exception will be thrown before calling this method. - if (oldVisibleFile != null && newVisibleFile != null) { - final long token = Binder.clearCallingIdentity(); - - try { - final ContentResolver resolver = getContext().getContentResolver(); - final Uri externalUri = newVisibleFile.isDirectory() - ? MediaStore.Files.getDirectoryUri("external") - : MediaStore.Files.getContentUri("external"); - - ContentValues values = new ContentValues(); - values.put(MediaStore.Files.FileColumns.DATA, newVisibleFile.getAbsolutePath()); - - // Logic borrowed from MtpDatabase. - // note - we are relying on a special case in MediaProvider.update() to update - // the paths for all children in the case where this is a directory. - final String path = oldVisibleFile.getAbsolutePath(); - resolver.update(externalUri, - values, - "_data LIKE ? AND lower(_data)=lower(?)", - new String[]{path, path}); - } finally { - Binder.restoreCallingIdentity(token); - } + if (oldVisibleFile != null) { + MediaStore.scanFile(getContext(), oldVisibleFile); + } + if (newVisibleFile != null) { + MediaStore.scanFile(getContext(), newVisibleFile); } } diff --git a/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl index 69d9ccc9825b..b5f2147784c0 100644 --- a/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl +++ b/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl @@ -31,4 +31,5 @@ interface IMultiClientInputMethodPrivilegedOperations { in IMultiClientInputMethodSession multiClientSession, in InputChannel writeChannel); void reportImeWindowTarget(int clientId, int targetWindowHandle, in IBinder imeWindowToken); boolean isUidAllowedOnDisplay(int displayId, int uid); + void setActive(int clientId, boolean active); } diff --git a/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java index 922011707c4a..1cf68872e2cf 100644 --- a/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java +++ b/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java @@ -212,4 +212,21 @@ public class MultiClientInputMethodPrivilegedOperations { } } + /** + * Calls {@link IMultiClientInputMethodPrivilegedOperations#setActive(int, boolean)}. + * @param clientId client ID to be set active/inactive + * @param active {@code true} set set active. + */ + @AnyThread + public void setActive(int clientId, boolean active) { + final IMultiClientInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); + if (ops == null) { + return; + } + try { + ops.setActive(clientId, active); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index afdeb1b602d7..a295bd21b20f 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -566,7 +566,18 @@ public final class Zygote { System.exit(-1); } finally { IoUtils.closeQuietly(sessionSocket); - IoUtils.closeQuietly(usapPoolSocket); + + try { + // This socket is closed using Os.close due to an issue with the implementation of + // LocalSocketImp.close. Because the raw FD is created by init and then loaded from + // an environment variable (as opposed to being created by the LocalSocketImpl + // itself) the current implementation will not actually close the underlying FD. + // + // See b/130309968 for discussion of this issue. + Os.close(usapPoolSocket.getFileDescriptor()); + } catch (ErrnoException ex) { + Log.e("USAP", "Failed to close USAP pool socket: " + ex.getMessage()); + } } try { diff --git a/core/java/com/android/internal/util/TrafficStatsConstants.java b/core/java/com/android/internal/util/TrafficStatsConstants.java new file mode 100644 index 000000000000..2806ae2f9298 --- /dev/null +++ b/core/java/com/android/internal/util/TrafficStatsConstants.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +/** + * Constants for traffic stats. + * @hide + */ +public class TrafficStatsConstants { + // These tags are used by the network stack to do traffic for its own purposes. Traffic + // tagged with these will be counted toward the network stack and must stay inside the + // range defined by + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_START} and + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_END}. + public static final int TAG_SYSTEM_DHCP = 0xFFFFFE01; + public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFE02; + public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFE03; + + public static final int TAG_SYSTEM_NTP = 0xFFFFFF41; + public static final int TAG_SYSTEM_GPS = 0xFFFFFF44; + public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; + + // These tags are used by the network stack to do traffic on behalf of apps. Traffic + // tagged with these will be counted toward the app on behalf of which the network + // stack is doing this traffic. These values must stay inside the range defined by + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}. + public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81; +} diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index b6ee0fe782a6..f2665020b49e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -678,6 +678,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX]; char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX]; char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX]; + char corePlatformApiPolicyBuf[sizeof("-Xcore-platform-api-policy:") + PROPERTY_VALUE_MAX]; char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX]; char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX]; std::string fingerprintBuf; @@ -1024,6 +1025,16 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) addOption("--generate-mini-debug-info"); } + // If set, the property below can be used to enable core platform API violation reporting. + property_get("persist.debug.dalvik.vm.core_platform_api_policy", propBuf, ""); + if (propBuf[0] != '\0') { + snprintf(corePlatformApiPolicyBuf, + sizeof(corePlatformApiPolicyBuf), + "-Xcore-platform-api-policy:%s", + propBuf); + addOption(corePlatformApiPolicyBuf); + } + /* * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will * contain the fingerprint and can be parsed. diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp index 19a1c7212fae..a62dd7c4048f 100644 --- a/core/jni/android_nio_utils.cpp +++ b/core/jni/android_nio_utils.cpp @@ -18,42 +18,51 @@ #include "core_jni_helpers.h" -void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { - assert(array); +namespace { +void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) { + assert(array); jint position; jint limit; jint elementSizeShift; jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); if (pointer != 0L) { + *array = nullptr; + *elements = nullptr; pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer); *array = jniGetNioBufferBaseArray(_env, buffer); - void * data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return reinterpret_cast<void*>(reinterpret_cast<char*>(data) + offset); + *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); + return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset); } +void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) { + _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT); +} + +} // namespace + +void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { + void* elements; + return getPointer(_env, buffer, array, &elements); +} -void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, - jboolean commit) { - _env->ReleasePrimitiveArrayCritical(array, data, - commit ? 0 : JNI_ABORT); +void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { + releasePointer(_env, array, data, commit); } /////////////////////////////////////////////////////////////////////////////// -android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, - jboolean commit) { +android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) { fEnv = env; fCommit = commit; - fPointer = android::nio_getPointer(env, nioBuffer, &fArray); + fPointer = getPointer(env, nioBuffer, &fArray, &fElements); } android::AutoBufferPointer::~AutoBufferPointer() { - if (NULL != fArray) { - android::nio_releasePointer(fEnv, fArray, fPointer, fCommit); + if (nullptr != fArray) { + releasePointer(fEnv, fArray, fElements, fCommit); } } diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h index c634cb917719..7c9acd2638da 100644 --- a/core/jni/android_nio_utils.h +++ b/core/jni/android_nio_utils.h @@ -20,7 +20,7 @@ #include <android_runtime/AndroidRuntime.h> namespace android { - + /** * Given an nio.Buffer, return a pointer to it, beginning at its current * position. The returned pointer is only valid for the current JNI stack-frame. @@ -63,9 +63,10 @@ public: private: JNIEnv* fEnv; - void* fPointer; - jarray fArray; - jboolean fCommit; + void* fPointer; // pointer to current buffer position. + void* fElements; // pointer to array element 0 (may be directly in fArray or a copy). + jarray fArray; // pointer to array on managed heap. + jboolean fCommit; // commit data to source if required (when fElements is a copy of fArray). }; } /* namespace android */ diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto index c35706501c3d..566861b6e836 100644 --- a/core/proto/android/os/enums.proto +++ b/core/proto/android/os/enums.proto @@ -78,6 +78,41 @@ enum TemperatureTypeEnum { TEMPERATURE_TYPE_NPU = 9; } +// Device throttling severity +// These constants are defined in hardware/interfaces/thermal/2.0/types.hal. +// Any change to the types in the thermal hal should be made here as well. +enum ThrottlingSeverityEnum { + // Not under throttling. + NONE = 0; + // Light throttling where UX is not impacted. + LIGHT = 1; + // Moderate throttling where UX is not largely impacted. + MODERATE = 2; + // Severe throttling where UX is largely impacted. + // Similar to 1.0 throttlingThreshold. + SEVERE = 3; + // Platform has done everything to reduce power. + CRITICAL = 4; + // Key components in platform are shutting down due to thermal condition. + // Device functionalities will be limited. + EMERGENCY = 5; + // Need shutdown immediately. + SHUTDOWN = 6; +}; + +// Device cooling device types. +// These constants are defined in hardware/interfaces/thermal/2.0/types.hal. +// Any change to the types in the thermal hal should be made here as well. +enum CoolingTypeEnum { + FAN = 0; + BATTERY = 1; + CPU = 2; + GPU = 3; + MODEM = 4; + NPU = 5; + COMPONENT = 6; +}; + // Wakelock types, primarily used by android/os/PowerManager.java. enum WakeLockLevelEnum { // NOTE: Wake lock levels were previously defined as a bit field, except diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto index 589a6a71d5fd..0db74243222c 100644 --- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto +++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto @@ -145,4 +145,8 @@ enum EventId { ESTABLISH_VPN = 118; SET_NETWORK_LOGGING_ENABLED = 119; RETRIEVE_NETWORK_LOGS = 120; + PROVISIONING_PREPARE_TOTAL_TIME_MS = 121; + PROVISIONING_PREPARE_STARTED = 122; + PROVISIONING_PREPARE_COMPLETED = 123; + PROVISIONING_FLOW_TYPE = 124; } diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml index 371bcfef7ec9..9fa7c5498ea6 100644 --- a/core/res/res/anim/activity_close_enter.xml +++ b/core/res/res/anim/activity_close_enter.xml @@ -19,15 +19,16 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> - <translate - android:fromYDelta="-2%" - android:toYDelta="0" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="425"/> - <alpha - android:fromAlpha="0.9" - android:toAlpha="1.0" - android:interpolator="@interpolator/activity_close_dim" - android:startOffset="0" - android:duration="425"/> + <scale + android:fromXScale="1.1" + android:toXScale="1" + android:fromYScale="1.1" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:duration="400"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml index d87f1003def5..1599ae8cb19f 100644 --- a/core/res/res/anim/activity_close_exit.xml +++ b/core/res/res/anim/activity_close_exit.xml @@ -20,25 +20,25 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top"> - <translate - android:fromYDelta="0" - android:toYDelta="4.1%" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="425"/> - <cliprect - android:fromLeft="0%" - android:fromTop="0%" - android:fromRight="100%" - android:fromBottom="100%" - android:toLeft="0%" - android:toTop="95.9%" - android:toRight="100%" - android:toBottom="100%" - android:interpolator="@interpolator/fast_out_extra_slow_in" - android:duration="425"/> <alpha - android:fromAlpha="1.0" - android:toAlpha="1.0" - android:interpolator="@interpolator/fast_out_linear_in" - android:duration="425"/> + android:fromAlpha="1" + android:toAlpha="0.0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="33" + android:duration="50"/> + <scale + android:fromXScale="1" + android:toXScale="0.9" + android:fromYScale="1" + android:toYScale="0.9" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:duration="400"/> </set> diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml index cb0307026e2f..38d3e8ed06ce 100644 --- a/core/res/res/anim/activity_open_enter.xml +++ b/core/res/res/anim/activity_open_enter.xml @@ -18,20 +18,25 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> - <translate - android:fromYDelta="4.1%" - android:toYDelta="0" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="425"/> - <cliprect - android:fromLeft="0%" - android:fromTop="95.9%" - android:fromRight="100%" - android:fromBottom="100%" - android:toLeft="0%" - android:toTop="0%" - android:toRight="100%" - android:toBottom="100%" + <alpha + android:fromAlpha="0" + android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="50" + android:duration="50"/> + <scale + android:fromXScale="0.85" + android:toXScale="1" + android:fromYScale="0.85" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" android:interpolator="@interpolator/fast_out_extra_slow_in" - android:duration="425"/> + android:duration="400"/> </set> diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml index d52b150391fb..3865d2149f42 100644 --- a/core/res/res/anim/activity_open_exit.xml +++ b/core/res/res/anim/activity_open_exit.xml @@ -18,14 +18,28 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> - <translate - android:fromYDelta="0" - android:toYDelta="-2%" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="425"/> + + <!-- Fade out, over a black surface, which simulates a black scrim --> <alpha - android:fromAlpha="1.0" - android:toAlpha="0.9" + android:fromAlpha="1" + android:toAlpha="0.4" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" android:interpolator="@interpolator/linear" - android:duration="117"/> + android:startOffset="83" + android:duration="167"/> + + <scale + android:fromXScale="1" + android:toXScale="1.05" + android:fromYScale="1" + android:toYScale="1.05" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:duration="400"/> </set>
\ No newline at end of file diff --git a/core/res/res/drawable/chooser_row_layer_list.xml b/core/res/res/drawable/chooser_row_layer_list.xml index 0fb26e13fe57..080081521ddf 100644 --- a/core/res/res/drawable/chooser_row_layer_list.xml +++ b/core/res/res/drawable/chooser_row_layer_list.xml @@ -17,7 +17,7 @@ */ --> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:bottom="-2dp" android:left="-2dp" android:right="-2dp"> + <item android:bottom="-5dp" android:left="-5dp" android:right="-5dp"> <shape android:shape="rectangle"> <stroke android:width="1dp" android:color="@color/chooser_row_divider"/> </shape> diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml index 45287002ebf7..f3ca0af767b1 100644 --- a/core/res/res/layout/chooser_grid_preview_text.xml +++ b/core/res/res/layout/chooser_grid_preview_text.xml @@ -24,9 +24,9 @@ android:layout_height="wrap_content" android:orientation="vertical" android:paddingBottom="@dimen/chooser_view_spacing" - android:background="?attr/colorBackgroundFloating"> + android:background="?android:attr/colorBackgroundFloating"> - <LinearLayout + <RelativeLayout android:layout_width="@dimen/chooser_preview_width" android:layout_height="wrap_content" android:layout_gravity="center" @@ -35,27 +35,51 @@ android:paddingRight="@dimen/chooser_edge_margin_normal" android:layout_marginBottom="@dimen/chooser_view_spacing" android:id="@+id/content_preview_text_layout"> + <TextView android:id="@+id/content_preview_text" - android:layout_width="0dp" - android:layout_weight="1" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" + android:layout_alignParentStart="true" + android:layout_toStartOf="@id/copy_button" + android:layout_centerVertical="true" android:ellipsize="end" - android:gravity="start|top" - android:paddingRight="@dimen/chooser_view_spacing" + android:textColor="?android:attr/textColorPrimary" android:maxLines="2"/> - <ImageButton + + <LinearLayout android:id="@+id/copy_button" - android:layout_width="48dp" - android:layout_height="48dp" - android:padding="12dp" + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_alignParentEnd="true" + android:layout_marginStart="@dimen/chooser_view_spacing" android:gravity="center" - android:layout_gravity="center_vertical" - android:src="@drawable/ic_content_copy_gm2" + android:minWidth="48dp" + android:minHeight="48dp" android:clickable="true" - android:background="?attr/selectableItemBackgroundBorderless"/> - </LinearLayout> + android:background="?android:attr/selectableItemBackgroundBorderless"> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:gravity="top|center_horizontal" + android:src="@drawable/ic_content_copy_gm2" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:gravity="center_horizontal" + android:text="@string/copy" + android:textColor="?android:textColorSecondary" + android:textSize="12sp" + android:maxWidth="72dp" + android:maxLines="2" + android:ellipsize="end" /> + </LinearLayout> + </RelativeLayout> <!-- Required sub-layout so we can get the nice rounded corners--> <!-- around this section --> @@ -88,7 +112,8 @@ android:layout_gravity="center_vertical" android:ellipsize="end" android:maxLines="2" - android:textSize="20sp"/> + android:textSize="20sp" + android:textColor="?android:attr/textColorPrimary"/> </LinearLayout> </LinearLayout> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index ed8f2c196b72..ab9a298f3060 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2485,24 +2485,7 @@ <flag name="noExcludeDescendants" value="0x8" /> </attr> - <!-- Hints the Android System whether the view node associated with this View should be - use for content capture purposes. --> - <attr name="importantForContentCapture"> - <!-- Let the Android System use its heuristics to determine if the view is important for content capture. --> - <flag name="auto" value="0" /> - <!-- Hint the Android System that this view is important for content capture, - and its children (if any) will be traversed.. --> - <flag name="yes" value="0x1" /> - <!-- Hint the Android System that this view is *not* important for content capture, - but its children (if any) will be traversed.. --> - <flag name="no" value="0x2" /> - <!-- Hint the Android System that this view is important for content capture, - but its children (if any) will not be traversed. --> - <flag name="yesExcludeDescendants" value="0x4" /> - <!-- Hint the Android System that this view is *not* important for content capture, - and its children (if any) will not be traversed. --> - <flag name="noExcludeDescendants" value="0x8" /> - </attr> + <attr name="__removed6" /> <!-- Boolean that controls whether a view can take focus while in touch mode. If this is true for a view, that view can gain focus when clicked on, and can keep diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 47c243ca1e04..bfa57e46984b 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1684,18 +1684,27 @@ This flag is turned on by default. <em>This attribute is usable only by system apps. </em> --> <attr name="allowClearUserDataOnFailedRestore"/> - <!-- If {@code true} the app's non sensitive audio can be capture by other apps with - {@code AudioPlaybackCaptureConfiguration} and a {@code MediaProjection}. + <!-- If {@code true} the app's non sensitive audio can be captured by other apps with + {@link android.media.AudioPlaybackCaptureConfiguration} and a + {@link android.media.projection.MediaProjection}. + + If {@code false} the audio played by the application will never be captured by non + system apps. It is equivalent to limiting + {@link android.media.AudioManager#setAllowedCapturePolicy(int)} to + {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}. <p> Non sensitive audio is defined as audio whose {@code AttributeUsage} is {@code USAGE_UNKNOWN}), {@code USAGE_MEDIA}) or {@code USAGE_GAME}). - All other usages (eg. {@code USAGE_VOICE_COMMUNICATION}) will not be captured. + All other usages like {@code USAGE_VOICE_COMMUNICATION} will not be captured. <p> The default value is: - {@code true} for apps with targetSdkVersion >= 29 (Q). - {@code false} for apps with targetSdkVersion < 29. + + <p> + See {@link android.media.AudioPlaybackCaptureConfiguration} for more detail. --> <attr name="allowAudioPlaybackCapture" format="boolean" /> <!-- If {@code true} this app allows shared/external storage media to be @@ -2814,6 +2823,9 @@ case-sensitive, unlike formal RFC MIME types. As a result, MIME types here should always use lower case letters.</em></p> --> <attr name="mimeType" /> + <!-- The identifier to assign to the intent, as per + {@link android.content.Intent#setIdentifier Intent.setIdentifier()}. --> + <attr name="identifier" format="string" /> <!-- The package part of the ComponentName to assign to the Intent, as per {@link android.content.Intent#setComponent Intent.setComponent()}. --> <attr name="targetPackage" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f27f34ae3420..526818949b3d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1971,10 +1971,6 @@ <bool name="config_showDefaultEmergency">false</bool> <!-- Whether the default home settings should be shown. --> <bool name="config_showDefaultHome">true</bool> - <!-- The name of the package that will hold the music role by default. --> - <string name="config_defaultMusic" translatable="false">com.android.music</string> - <!-- The name of the package that will hold the gallery role by default. --> - <string name="config_defaultGallery" translatable="false">com.android.gallery3d</string> <!-- Enable/disable default bluetooth profiles: HSP_AG, ObexObjectPush, Audio, NAP --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 626518c97ac1..b7d61c8f8d39 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2922,7 +2922,7 @@ <public name="settingsSliceUri" /> <public name="shell" /> <public name="interactiveUiTimeout" /> - <public name="importantForContentCapture" /> + <public name="__removed6" /> <public name="supportsMultipleDisplays" /> <public name="useAppZygote" /> <public name="__removed1" /> @@ -2945,6 +2945,7 @@ <public name="allowExternalStorageSandbox"/> <public name="ensuringStatusBarContrastWhenTransparent" /> <public name="ensuringNavigationBarContrastWhenTransparent" /> + <public name="identifier" /> </public-group> <public-group type="drawable" first-id="0x010800b4"> @@ -2987,10 +2988,6 @@ <public name="config_defaultDialer" /> <!-- @hide @SystemApi --> <public name="config_defaultSms" /> - <!-- @hide @SystemApi --> - <public name="config_defaultMusic" /> - <!-- @hide @SystemApi --> - <public name="config_defaultGallery" /> </public-group> <public-group type="bool" first-id="0x01110000"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f8a2ac9f3e18..4bd2cc758cbb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1521,10 +1521,10 @@ <string name="face_acquired_too_high">Move phone higher.</string> <!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] --> <string name="face_acquired_too_low">Move phone lower.</string> - <!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_right">Move phone to the right.</string> - <!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_left">Move phone to the left.</string> + <!-- Message shown during face acquisition when only the right part of the user's face was detected [CHAR LIMIT=50] --> + <string name="face_acquired_too_right">Move phone to the left.</string> + <!-- Message shown during face acquisition when only the left part of the user's face was detected [CHAR LIMIT=50] --> + <string name="face_acquired_too_left">Move phone to the right.</string> <!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] --> <string name="face_acquired_poor_gaze">Look at the screen with your eyes open.</string> <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] --> diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 9cb34895dea4..711eaa7edc2a 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -38,6 +38,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import android.view.Display; +import android.view.View; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; @@ -153,6 +154,34 @@ public class ActivityThreadTest { } @Test + public void testHandleActivity_assetsChanged() { + final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); + + final IBinder[] token = new IBinder[1]; + final View[] decorView = new View[1]; + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final ActivityThread activityThread = activity.getActivityThread(); + + token[0] = activity.getActivityToken(); + decorView[0] = activity.getWindow().getDecorView(); + + // Relaunches all activities + activityThread.handleApplicationInfoChanged(activity.getApplicationInfo()); + }); + + final View[] newDecorView = new View[1]; + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final ActivityThread activityThread = activity.getActivityThread(); + + final Activity newActivity = activityThread.getActivity(token[0]); + newDecorView[0] = activity.getWindow().getDecorView(); + }); + + assertEquals("Window must be preserved", decorView[0], newDecorView[0]); + } + + @Test public void testHandleActivityConfigurationChanged_DropStaleConfigurations() { final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java index d2a1dd9a7b5c..4bee24385cc5 100644 --- a/core/tests/coretests/src/android/graphics/BitmapTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapTest.java @@ -22,6 +22,8 @@ import androidx.test.filters.SmallTest; import junit.framework.TestCase; +import java.nio.ByteBuffer; + public class BitmapTest extends TestCase { @SmallTest @@ -262,4 +264,74 @@ public class BitmapTest extends TestCase { assertFalse(hardwareBitmap.isMutable()); assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), hardwareBitmap.getColorSpace()); } + + @SmallTest + public void testCopyWithDirectBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to direct buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final byte padValue = 0x5a; + final int bufferSize = pad + width * height * 2 + pad; + ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); + + // Write padding + directBuffer.put(0, padValue); + directBuffer.put(directBuffer.limit() - 1, padValue); + + // Copy bitmap + directBuffer.position(pad); + bm1.copyPixelsToBuffer(directBuffer); + assertEquals(directBuffer.position(), pad + width * height * 2); + + // Check padding + assertEquals(directBuffer.get(0), padValue); + assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); + + // Create bitmap from direct buffer and check match. + directBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(directBuffer); + assertTrue(bm2.sameAs(bm1)); + } + + @SmallTest + public void testCopyWithHeapBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final byte padValue = 0x5a; + final int bufferSize = pad + width * height * 2 + pad; + ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); + + // Write padding + heapBuffer.put(0, padValue); + heapBuffer.put(heapBuffer.limit() - 1, padValue); + + // Copy bitmap + heapBuffer.position(pad); + bm1.copyPixelsToBuffer(heapBuffer); + assertEquals(heapBuffer.position(), pad + width * height * 2); + + // Check padding + assertEquals(heapBuffer.get(0), padValue); + assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); + + // Create bitmap from heap buffer and check match. + heapBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(heapBuffer); + assertTrue(bm2.sameAs(bm1)); + } } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index fafd8333f236..0e94abc0dcac 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -709,7 +709,9 @@ public class SettingsBackupTest { Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, Settings.Secure.LOCATION_ACCESS_CHECK_INTERVAL_MILLIS, Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS, - Settings.Secure.BIOMETRIC_DEBUG_ENABLED); + Settings.Secure.BIOMETRIC_DEBUG_ENABLED, + Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, + Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index ebbbdec7d376..bdd3038cfee5 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -39,11 +39,13 @@ import android.platform.test.annotations.Presubmit; import android.util.SparseArray; import android.view.SurfaceControl.Transaction; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; +import android.view.test.InsetsModeSession; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -62,7 +64,6 @@ import java.util.List; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsAnimationControlImplTest { @@ -72,15 +73,25 @@ public class InsetsAnimationControlImplTest { private SurfaceControl mTopLeash; private SurfaceControl mNavLeash; private InsetsState mInsetsState; + private static InsetsModeSession sInsetsModeSession; @Mock Transaction mMockTransaction; @Mock InsetsController mMockController; @Mock WindowInsetsAnimationControlListener mMockListener; @Mock SyncRtSurfaceTransactionApplier mMockTransactionApplier; + @BeforeClass + public static void setupOnce() { + sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL); + } + + @AfterClass + public static void tearDownOnce() throws Exception { + sInsetsModeSession.close(); + } + @Before public void setup() { - ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL; MockitoAnnotations.initMocks(this); mTopLeash = new SurfaceControl.Builder(mSession) .setName("testSurface") diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 4d8d3f68f875..1e558287e21b 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -43,7 +43,6 @@ import android.view.WindowManager.LayoutParams; import android.widget.TextView; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; @@ -63,7 +62,6 @@ import java.util.concurrent.CountDownLatch; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsControllerTest { diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java index a32fa778e736..971e143927b3 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java @@ -34,7 +34,6 @@ import android.view.WindowManager.LayoutParams; import android.widget.TextView; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; @@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsSourceConsumerTest { diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java index b55a9c600a61..533a58ef1dfb 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java @@ -24,7 +24,6 @@ import android.graphics.Insets; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; @@ -41,7 +40,6 @@ import org.junit.runner.RunWith; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsSourceTest { diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index 8e167da84e08..a73269a81b11 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -40,7 +40,6 @@ import android.util.SparseIntArray; import android.view.WindowInsets.Type; import android.view.test.InsetsModeSession; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; @@ -56,7 +55,6 @@ import org.junit.runner.RunWith; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsStateTest { diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java index cd885e0b9bcf..7c255c9168cc 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java @@ -47,6 +47,6 @@ public class ContentCaptureManagerTest { @Test public void testRemoveUserData_invalid() { - assertThrows(NullPointerException.class, () -> mManager.removeUserData(null)); + assertThrows(NullPointerException.class, () -> mManager.removeData(null)); } } diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 00b4a225c55f..ac039dddb66c 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -42,6 +42,7 @@ import android.content.ClipboardManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; @@ -53,7 +54,6 @@ import android.metrics.LogMaker; import android.net.Uri; import android.service.chooser.ChooserTarget; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; @@ -62,10 +62,14 @@ import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import java.util.Arrays; +import java.util.Collection; +import java.util.function.Function; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -75,21 +79,48 @@ import java.util.List; /** * Chooser activity instrumentation tests */ -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) public class ChooserActivityTest { + private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm; + private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM = + pm -> { + PackageManager mock = Mockito.spy(pm); + when(mock.getAppPredictionServicePackageName()).thenReturn(null); + return mock; + }; + + @Parameterized.Parameters + public static Collection packageManagers() { + return Arrays.asList(new Object[][] { + {0, "Default PackageManager", DEFAULT_PM}, + {1, "No App Prediction Service", NO_APP_PREDICTION_SERVICE_PM} + }); + } + private static final int CONTENT_PREVIEW_IMAGE = 1; private static final int CONTENT_PREVIEW_FILE = 2; private static final int CONTENT_PREVIEW_TEXT = 3; + private Function<PackageManager, PackageManager> mPackageManagerOverride; + private int mTestNum; @Rule public ActivityTestRule<ChooserWrapperActivity> mActivityRule = new ActivityTestRule<>(ChooserWrapperActivity.class, false, false); + public ChooserActivityTest( + int testNum, + String testName, + Function<PackageManager, PackageManager> packageManagerOverride) { + mPackageManagerOverride = packageManagerOverride; + mTestNum = testNum; + } + @Before public void cleanOverrideData() { sOverrides.reset(); + sOverrides.createPackageManager = mPackageManagerOverride; } @Test diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp new file mode 100644 index 000000000000..ae3ff8612eee --- /dev/null +++ b/core/tests/mockingcoretests/Android.bp @@ -0,0 +1,53 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test { + name: "FrameworksMockingCoreTests", + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + "frameworks-base-testutils", + "services.core", + "androidx.test.runner", + "androidx.test.rules", + "androidx.test.ext.junit", + "mockito-target-extended-minus-junit4", + "platform-test-annotations", + "truth-prebuilt", + "testables", + "ub-uiautomator", + ], + + libs: [ + "android.test.base", + "android.test.mock", + "android.test.runner", + ], + + // These are not normally accessible from apps so they must be explicitly included. + jni_libs: [ + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + + platform_apis: true, + test_suites: ["device-tests"], + + certificate: "platform", +} diff --git a/core/tests/mockingcoretests/AndroidManifest.xml b/core/tests/mockingcoretests/AndroidManifest.xml new file mode 100644 index 000000000000..b9ee0852366d --- /dev/null +++ b/core/tests/mockingcoretests/AndroidManifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + android:installLocation="internalOnly" + package="com.android.frameworks.mockingcoretests" + android:sharedUserId="com.android.uid.test"> + + <application android:supportsRtl="true" android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + + <activity android:name="android.app.activity.ActivityThreadClientTest$TestActivity" + android:exported="true"> + </activity> + + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.frameworks.mockingcoretests" + android:label="Frameworks Mocking Core Tests" /> +</manifest> diff --git a/core/tests/mockingcoretests/AndroidTest.xml b/core/tests/mockingcoretests/AndroidTest.xml new file mode 100644 index 000000000000..47aa41003336 --- /dev/null +++ b/core/tests/mockingcoretests/AndroidTest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<configuration description="Runs Frameworks Mocking Core Tests."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="FrameworksMockingCoreTests.apk" /> + </target_preparer> + <option name="test-tag" value="FrameworksMockingCoreTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.frameworks.mockingcoretests" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration> diff --git a/core/tests/mockingcoretests/README b/core/tests/mockingcoretests/README new file mode 100644 index 000000000000..c0f65c29a8a4 --- /dev/null +++ b/core/tests/mockingcoretests/README @@ -0,0 +1,33 @@ +* Copyright (C) 2019 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + + +INTRODUCTION + +The Android platform core tests that require additional mocking capabilities and use Extended +Mockito, such as the ability to stub static methods. ExtendedMockito is not fully compatible with +regular Mockito library, so tests that use it have to be verified and adapted. For that reason a +separate module is used instead of adding to FrameworksCoreTests. + +For more information about ExtendedMockito see documentation of +com.android.dx.mockito.inline.extended.ExtendedMockito class. + +See ../coretests/README for more information on FrameworksCoreTests. + + +INSTRUCTIONS + +To build, install and run: + + atest FrameworksMockingCoreTests diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java new file mode 100644 index 000000000000..86d55ea4f5c2 --- /dev/null +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.activity; + +import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE; +import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY; +import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE; +import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; +import static android.app.servertransaction.ActivityLifecycleItem.ON_START; +import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.app.ActivityTaskManager; +import android.app.ActivityThread; +import android.app.ActivityThread.ActivityClientRecord; +import android.app.IActivityTaskManager; +import android.app.servertransaction.PendingTransactionActions; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.os.Binder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.view.WindowManagerGlobal; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.MediumTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +/** + * Test for verifying {@link android.app.ActivityThread} class. + * + * <p>Build/Install/Run: + * atest FrameworksMockingCoreTests:android.app.activity.ActivityThreadClientTest + * + * <p>This test class is a part of Window Manager Service tests and specified in + * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. + */ +@RunWith(AndroidJUnit4.class) +@MediumTest +public class ActivityThreadClientTest { + + @Test + @UiThreadTest + public void testWindowVisibilityChange_OnCreate() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + clientSession.launchActivity(r); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.changeVisibility(r, true); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.changeVisibility(r, false); + assertEquals(ON_CREATE, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testWindowVisibilityChange_OnCreate_Finished() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + Activity activity = clientSession.launchActivity(r); + activity.finish(); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.changeVisibility(r, true); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.changeVisibility(r, false); + assertEquals(ON_CREATE, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testWindowVisibilityChange_OnStart() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + clientSession.launchActivity(r); + clientSession.startActivity(r); + assertEquals(ON_START, r.getLifecycleState()); + + clientSession.changeVisibility(r, false); + assertEquals(ON_STOP, r.getLifecycleState()); + + clientSession.changeVisibility(r, true); + assertEquals(ON_START, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testWindowVisibilityChange_OnStart_Finished() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + Activity activity = clientSession.launchActivity(r); + clientSession.startActivity(r); + activity.finish(); + assertEquals(ON_START, r.getLifecycleState()); + + clientSession.changeVisibility(r, false); + assertEquals(ON_STOP, r.getLifecycleState()); + + clientSession.changeVisibility(r, true); + assertEquals(ON_START, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testWindowVisibilityChange_OnResume() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + clientSession.launchActivity(r); + clientSession.startActivity(r); + clientSession.resumeActivity(r); + assertEquals(ON_RESUME, r.getLifecycleState()); + + clientSession.changeVisibility(r, false); + assertEquals(ON_STOP, r.getLifecycleState()); + + clientSession.changeVisibility(r, true); + assertEquals(ON_START, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testWindowVisibilityChange_OnPause() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + clientSession.launchActivity(r); + clientSession.startActivity(r); + clientSession.resumeActivity(r); + clientSession.pauseActivity(r); + assertEquals(ON_PAUSE, r.getLifecycleState()); + + clientSession.changeVisibility(r, false); + assertEquals(ON_STOP, r.getLifecycleState()); + + clientSession.changeVisibility(r, true); + assertEquals(ON_START, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testWindowVisibilityChange_OnStop() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + clientSession.launchActivity(r); + clientSession.startActivity(r); + clientSession.resumeActivity(r); + clientSession.pauseActivity(r); + clientSession.stopActivity(r); + assertEquals(ON_STOP, r.getLifecycleState()); + + clientSession.changeVisibility(r, true); + assertEquals(ON_START, r.getLifecycleState()); + + clientSession.changeVisibility(r, false); + assertEquals(ON_STOP, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testLifecycleAfterFinished_OnCreate() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + Activity activity = clientSession.launchActivity(r); + activity.finish(); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.startActivity(r); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.resumeActivity(r); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.pauseActivity(r); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.stopActivity(r); + assertEquals(ON_CREATE, r.getLifecycleState()); + + clientSession.destroyActivity(r); + assertEquals(ON_DESTROY, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testLifecycleAfterFinished_OnStart() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + Activity activity = clientSession.launchActivity(r); + clientSession.startActivity(r); + activity.finish(); + assertEquals(ON_START, r.getLifecycleState()); + + clientSession.resumeActivity(r); + assertEquals(ON_START, r.getLifecycleState()); + + clientSession.pauseActivity(r); + assertEquals(ON_START, r.getLifecycleState()); + + clientSession.stopActivity(r); + assertEquals(ON_STOP, r.getLifecycleState()); + + clientSession.destroyActivity(r); + assertEquals(ON_DESTROY, r.getLifecycleState()); + } + } + + @Test + @UiThreadTest + public void testLifecycleAfterFinished_OnResume() throws Exception { + try (ClientMockSession clientSession = new ClientMockSession()) { + ActivityClientRecord r = clientSession.stubActivityRecord(); + + Activity activity = clientSession.launchActivity(r); + clientSession.startActivity(r); + clientSession.resumeActivity(r); + activity.finish(); + assertEquals(ON_RESUME, r.getLifecycleState()); + + clientSession.pauseActivity(r); + assertEquals(ON_PAUSE, r.getLifecycleState()); + + clientSession.stopActivity(r); + assertEquals(ON_STOP, r.getLifecycleState()); + + clientSession.destroyActivity(r); + assertEquals(ON_DESTROY, r.getLifecycleState()); + } + } + + private class ClientMockSession implements AutoCloseable { + private MockitoSession mMockSession; + private ActivityThread mThread; + + private ClientMockSession() throws RemoteException { + mThread = ActivityThread.currentActivityThread(); + mMockSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(ActivityTaskManager.class) + .spyStatic(WindowManagerGlobal.class) + .startMocking(); + doReturn(Mockito.mock(WindowManagerGlobal.class)) + .when(WindowManagerGlobal::getInstance); + IActivityTaskManager mockAtm = Mockito.mock(IActivityTaskManager.class); + doReturn(mockAtm).when(ActivityTaskManager::getService); + when(mockAtm.finishActivity(any(), anyInt(), any(), anyInt())).thenReturn(true); + } + + private Activity launchActivity(ActivityClientRecord r) { + return mThread.handleLaunchActivity(r, null /* pendingActions */, + null /* customIntent */); + } + + private void startActivity(ActivityClientRecord r) { + mThread.handleStartActivity(r, null /* pendingActions */); + } + + private void resumeActivity(ActivityClientRecord r) { + mThread.handleResumeActivity(r.token, true /* finalStateRequest */, + true /* isForward */, "test"); + } + + private void pauseActivity(ActivityClientRecord r) { + mThread.handlePauseActivity(r.token, false /* finished */, + false /* userLeaving */, 0 /* configChanges */, null /* pendingActions */, + "test"); + } + + private void stopActivity(ActivityClientRecord r) { + mThread.handleStopActivity(r.token, false /* show */, 0 /* configChanges */, + new PendingTransactionActions(), false /* finalStateRequest */, "test"); + } + + private void destroyActivity(ActivityClientRecord r) { + mThread.handleDestroyActivity(r.token, true /* finishing */, 0 /* configChanges */, + false /* getNonConfigInstance */, "test"); + } + + private void changeVisibility(ActivityClientRecord r, boolean show) { + mThread.handleWindowVisibility(r.token, show); + } + + private ActivityClientRecord stubActivityRecord() { + ComponentName component = new ComponentName( + InstrumentationRegistry.getInstrumentation().getContext(), TestActivity.class); + ActivityInfo info = new ActivityInfo(); + info.packageName = component.getPackageName(); + info.name = component.getClassName(); + info.exported = true; + info.applicationInfo = new ApplicationInfo(); + info.applicationInfo.packageName = info.packageName; + info.applicationInfo.uid = UserHandle.myUserId(); + + return new ActivityClientRecord(new Binder(), Intent.makeMainActivity(component), + 0 /* ident */, info, new Configuration(), + CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */, + null /* voiceInteractor */, null /* state */, null /* persistentState */, + null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */, + null /* profilerInfo */, mThread /* client */); + } + + @Override + public void close() { + mMockSession.finishMocking(); + } + } + + // Test activity + public static class TestActivity extends Activity { + } +} diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java index 99b6421d2bc7..267cb365748e 100644 --- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java @@ -163,6 +163,20 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { assertTrue(overlayManagerContainsPackage(APP_OVERLAY_PACKAGE_NAME)); } + @Test + public void changesPersistedWhenUninstallingDisabledOverlay() throws Exception { + getDevice().enableAdbRoot(); + assertFalse(getDevice().executeShellCommand("cat /data/system/overlays.xml") + .contains(APP_OVERLAY_PACKAGE_NAME)); + installPackage("OverlayHostTests_AppOverlayV1.apk"); + assertTrue(getDevice().executeShellCommand("cat /data/system/overlays.xml") + .contains(APP_OVERLAY_PACKAGE_NAME)); + uninstallPackage(APP_OVERLAY_PACKAGE_NAME); + delay(); + assertFalse(getDevice().executeShellCommand("cat /data/system/overlays.xml") + .contains(APP_OVERLAY_PACKAGE_NAME)); + } + private void delay() { try { Thread.sleep(1000); diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 11e4cb835d65..2ad2e76cc696 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -3510,6 +3510,7 @@ struct ResTable::Package ResStringPool keyStrings; size_t typeIdOffset; + bool definesOverlayable = false; }; // A group of objects describing a particular resource package. @@ -6861,6 +6862,10 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, ALOGW("Found multiple library tables, ignoring..."); } } else { + if (ctype == RES_TABLE_OVERLAYABLE_TYPE) { + package->definesOverlayable = true; + } + status_t err = validate_chunk(chunk, sizeof(ResChunk_header), endPos, "ResTable_package:unknown"); if (err != NO_ERROR) { @@ -7138,6 +7143,11 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, return UNKNOWN_ERROR; } + // Idmap is not aware of overlayable, exit since policy checks can't be done + if (targetResTable.mPackageGroups[0]->packages[0]->definesOverlayable) { + return UNKNOWN_ERROR; + } + const ResTable_package* targetPackageStruct = targetResTable.mPackageGroups[0]->packages[0]->package; const size_t tmpNameSize = arraysize(targetPackageStruct->name); diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 9b1f25986d56..99988542d619 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -17,8 +17,8 @@ #include "Properties.h" #include "Debug.h" #include "DeviceInfo.h" -#include "SkTraceEventCommon.h" #include "HWUIProperties.sysprop.h" +#include "SkTraceEventCommon.h" #include <algorithm> #include <cstdlib> @@ -67,7 +67,7 @@ bool Properties::debuggingEnabled = false; bool Properties::isolatedProcess = false; int Properties::contextPriority = 0; -int Properties::defaultRenderAhead = 0; +uint32_t Properties::defaultRenderAhead = 0; static int property_get_int(const char* key, int defaultValue) { char buf[PROPERTY_VALUE_MAX] = { @@ -130,12 +130,9 @@ bool Properties::load() { enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true); - defaultRenderAhead = std::max(0, std::min(2, property_get_int(PROPERTY_RENDERAHEAD, - render_ahead().value_or(0)))); - - if (defaultRenderAhead && sRenderPipelineType == RenderPipelineType::SkiaVulkan) { - ALOGW("hwui.render_ahead of %d ignored because pipeline is skiavk", defaultRenderAhead); - } + defaultRenderAhead = + std::max(0u, std::min(2u, static_cast<uint32_t>(property_get_int( + PROPERTY_RENDERAHEAD, render_ahead().value_or(0))))); return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 3e91c63fcbde..3105e58362ec 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -253,7 +253,7 @@ public: ANDROID_API static int contextPriority; - static int defaultRenderAhead; + static uint32_t defaultRenderAhead; private: static ProfileType sProfileType; diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp index cdad20ec6caa..dc53dd6c27c3 100644 --- a/libs/hwui/TreeInfo.cpp +++ b/libs/hwui/TreeInfo.cpp @@ -25,6 +25,7 @@ TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContex , prepareTextures(mode == MODE_FULL) , canvasContext(canvasContext) , damageGenerationId(canvasContext.getFrameNumber()) - , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {} + , disableForceDark(canvasContext.useForceDark() ? 0 : 1) + , screenSize(canvasContext.getNextFrameSize()) {} } // namespace android::uirenderer diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index 04eabac395f0..7e8d12fd4597 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -20,6 +20,7 @@ #include "utils/Macros.h" #include <utils/Timers.h> +#include "SkSize.h" #include <string> @@ -96,6 +97,8 @@ public: int disableForceDark; + const SkISize screenSize; + struct Out { bool hasFunctors = false; // This is only updated if evaluateAnimations is true diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index da905cf9e63a..5418b337c371 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -547,6 +547,11 @@ void Tree::Cache::clear() { } void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint) { + if (canvas->quickReject(bounds)) { + // The RenderNode is on screen, but the AVD is not. + return; + } + // Update the paint for any animatable properties SkPaint paint = inPaint; paint.setAlpha(mProperties.getRootAlpha() * 255); diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp index 8508274676fd..66aa8c203799 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.cpp +++ b/libs/hwui/pipeline/skia/ShaderCache.cpp @@ -15,6 +15,7 @@ */ #include "ShaderCache.h" +#include <GrContext.h> #include <log/log.h> #include <openssl/sha.h> #include <algorithm> @@ -23,7 +24,6 @@ #include "FileBlobCache.h" #include "Properties.h" #include "utils/TraceUtils.h" -#include <GrContext.h> namespace android { namespace uirenderer { diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 29d5ef233338..41bcfc25f5c1 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -22,6 +22,7 @@ #include "renderthread/CanvasContext.h" #include <SkImagePriv.h> +#include <SkPathOps.h> namespace android { namespace uirenderer { @@ -35,7 +36,7 @@ void SkiaDisplayList::syncContents(const WebViewSyncData& data) { animatedImage->syncProperties(); } for (auto& vectorDrawable : mVectorDrawables) { - vectorDrawable->syncProperties(); + vectorDrawable.first->syncProperties(); } } @@ -51,6 +52,29 @@ void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) } } +static bool intersects(const SkISize screenSize, const Matrix4& mat, const SkRect& bounds) { + Vector3 points[] = { Vector3 {bounds.fLeft, bounds.fTop, 0}, + Vector3 {bounds.fRight, bounds.fTop, 0}, + Vector3 {bounds.fRight, bounds.fBottom, 0}, + Vector3 {bounds.fLeft, bounds.fBottom, 0}}; + float minX, minY, maxX, maxY; + bool first = true; + for (auto& point : points) { + mat.mapPoint3d(point); + if (first) { + minX = maxX = point.x; + minY = maxY = point.y; + first = false; + } else { + minX = std::min(minX, point.x); + minY = std::min(minY, point.y); + maxX = std::max(maxX, point.x); + maxY = std::max(maxY, point.y); + } + } + return SkRect::Make(screenSize).intersects(SkRect::MakeLTRB(minX, minY, maxX, maxY)); +} + bool SkiaDisplayList::prepareListAndChildren( TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { @@ -107,15 +131,23 @@ bool SkiaDisplayList::prepareListAndChildren( } } - for (auto& vectorDrawable : mVectorDrawables) { + for (auto& vectorDrawablePair : mVectorDrawables) { // If any vector drawable in the display list needs update, damage the node. + auto& vectorDrawable = vectorDrawablePair.first; if (vectorDrawable->isDirty()) { - isDirty = true; - static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) - ->getVectorDrawables() - ->push_back(vectorDrawable); + Matrix4 totalMatrix; + info.damageAccumulator->computeCurrentTransform(&totalMatrix); + Matrix4 canvasMatrix(vectorDrawablePair.second); + totalMatrix.multiply(canvasMatrix); + const SkRect& bounds = vectorDrawable->properties().getBounds(); + if (intersects(info.screenSize, totalMatrix, bounds)) { + isDirty = true; + static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) + ->getVectorDrawables() + ->push_back(vectorDrawable); + vectorDrawable->setPropertyChangeWillBeConsumed(true); + } } - vectorDrawable->setPropertyChangeWillBeConsumed(true); } return isDirty; } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 3219ad1deeff..b79103787023 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -22,6 +22,7 @@ #include "TreeInfo.h" #include "hwui/AnimatedImageDrawable.h" #include "utils/LinearAllocator.h" +#include "utils/Pair.h" #include <deque> @@ -41,12 +42,6 @@ typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; namespace skiapipeline { -/** - * This class is intended to be self contained, but still subclasses from - * DisplayList to make it easier to support switching between the two at - * runtime. The downside of this inheritance is that we pay for the overhead - * of the parent class construction/destruction without any real benefit. - */ class SkiaDisplayList { public: size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); } @@ -156,7 +151,17 @@ public: std::deque<RenderNodeDrawable> mChildNodes; std::deque<FunctorDrawable*> mChildFunctors; std::vector<SkImage*> mMutableImages; - std::vector<VectorDrawableRoot*> mVectorDrawables; +private: + std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables; +public: + void appendVD(VectorDrawableRoot* r) { + appendVD(r, SkMatrix::I()); + } + + void appendVD(VectorDrawableRoot* r, const SkMatrix& mat) { + mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat)); + } + std::vector<AnimatedImageDrawable*> mAnimatedImages; DisplayListData mDisplayList; diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 570e895a012d..9248eadbd0ef 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -101,7 +101,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con SkiaPipeline::updateLighting(lightGeometry, lightInfo); renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, - SkMatrix::I()); + SkMatrix::I()); layerUpdateQueue->clear(); // Draw visual debugging features @@ -156,8 +156,23 @@ void SkiaOpenGLPipeline::onStop() { } } +static void setBufferCount(ANativeWindow* window, uint32_t extraBuffers) { + int query_value; + int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); + if (err != 0 || query_value < 0) { + ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); + return; + } + auto min_undequeued_buffers = static_cast<uint32_t>(query_value); + + int bufferCount = min_undequeued_buffers + 2 + extraBuffers; + ALOGD("Setting buffer count to %d, min_undequeued %u, extraBuffers %u", + bufferCount, min_undequeued_buffers, extraBuffers); + native_window_set_buffer_count(window, bufferCount); +} + bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, - ColorMode colorMode) { + ColorMode colorMode, uint32_t extraBuffers) { if (mEglSurface != EGL_NO_SURFACE) { mEglManager.destroySurface(mEglSurface); mEglSurface = EGL_NO_SURFACE; @@ -177,6 +192,7 @@ bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBeh if (mEglSurface != EGL_NO_SURFACE) { const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); + setBufferCount(surface, extraBuffers); return true; } diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 66929226a5e2..3fe0f92b1924 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -44,7 +44,7 @@ public: FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, - renderthread::ColorMode colorMode) override; + renderthread::ColorMode colorMode, uint32_t extraBuffers) override; void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 721a115c1381..ccc1701dcc0b 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -250,8 +250,9 @@ SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) { } if (mCaptureSequence > 0 || mPictureCapturedCallback) { mRecorder.reset(new SkPictureRecorder()); - SkCanvas* pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height(), nullptr, - SkPictureRecorder::kPlaybackDrawPicture_RecordFlag); + SkCanvas* pictureCanvas = + mRecorder->beginRecording(surface->width(), surface->height(), nullptr, + SkPictureRecorder::kPlaybackDrawPicture_RecordFlag); mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height()); mNwayCanvas->addCanvas(surface->getCanvas()); mNwayCanvas->addCanvas(pictureCanvas); @@ -276,8 +277,7 @@ void SkiaPipeline::endCapture(SkSurface* surface) { if (1 == mCaptureSequence) { savePictureAsync(data, mCapturedFile); } else { - savePictureAsync(data, - mCapturedFile + "_" + std::to_string(mCaptureSequence)); + savePictureAsync(data, mCapturedFile + "_" + std::to_string(mCaptureSequence)); } mCaptureSequence--; } @@ -327,7 +327,7 @@ static Rect nodeBounds(RenderNode& node) { auto& props = node.properties(); return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom()); } -} +} // namespace void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip, const std::vector<sp<RenderNode>>& nodes, bool opaque, @@ -464,10 +464,20 @@ void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) { // (3) Requires RGBA colors (instead of BGRA). static const uint32_t kOverdrawColors[2][6] = { { - 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, + 0x00000000, + 0x00000000, + 0x2f2f0000, + 0x2f002f00, + 0x3f00003f, + 0x7f00007f, }, { - 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, + 0x00000000, + 0x00000000, + 0x2f2f0000, + 0x4f004f4f, + 0x5f50335f, + 0x7f00007f, }, }; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index d9456355cb88..0a2894945dc8 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -142,8 +142,7 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { FunctorDrawable* functorDrawable; if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - functorDrawable = - mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas()); + functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas()); } else { functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas()); } @@ -153,7 +152,9 @@ void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { mRecorder.drawVectorDrawable(tree); - mDisplayList->mVectorDrawables.push_back(tree); + SkMatrix mat; + this->getMatrix(&mat); + mDisplayList->appendVD(tree, mat); } // ---------------------------------------------------------------------------- diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index edde6d3e05c0..e8cb219db320 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -18,12 +18,12 @@ #include "DeferredLayerUpdater.h" #include "Readback.h" +#include "ShaderCache.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" #include "VkInteropFunctorDrawable.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" -#include "ShaderCache.h" #include <SkSurface.h> #include <SkTypes.h> @@ -70,8 +70,8 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, con return false; } SkiaPipeline::updateLighting(lightGeometry, lightInfo); - renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - backBuffer, mVkSurface->getCurrentPreTransform()); + renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer, + mVkSurface->getCurrentPreTransform()); ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext()); layerUpdateQueue->clear(); @@ -116,7 +116,7 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() { void SkiaVulkanPipeline::onStop() {} bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, - ColorMode colorMode) { + ColorMode colorMode, uint32_t extraBuffers) { if (mVkSurface) { mVkManager.destroySurface(mVkSurface); mVkSurface = nullptr; @@ -125,8 +125,9 @@ bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBeh setSurfaceColorProperties(colorMode); if (surface) { mRenderThread.requireVkContext(); - mVkSurface = mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace, - mSurfaceColorType, mRenderThread.getGrContext()); + mVkSurface = + mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace, mSurfaceColorType, + mRenderThread.getGrContext(), extraBuffers); } return mVkSurface != nullptr; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 77a7ab171ee1..31734783de7f 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -43,7 +43,7 @@ public: FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, - renderthread::ColorMode colorMode) override; + renderthread::ColorMode colorMode, uint32_t extraBuffers) override; void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp index 1b9e53b21adb..112792611fc3 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp @@ -17,16 +17,16 @@ #include "VkFunctorDrawable.h" #include <private/hwui/DrawVkInfo.h> -#include "renderthread/VulkanManager.h" -#include "renderthread/RenderThread.h" -#include <SkAndroidFrameworkUtils.h> #include <GrBackendDrawableInfo.h> +#include <SkAndroidFrameworkUtils.h> #include <SkImage.h> #include <utils/Color.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> #include <vk/GrVkTypes.h> #include <thread> +#include "renderthread/RenderThread.h" +#include "renderthread/VulkanManager.h" #include "thread/ThreadBase.h" #include "utils/TimeUtils.h" @@ -64,13 +64,13 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) { SkMatrix44 mat4(mMatrix); VkFunctorDrawParams params{ - .width = mImageInfo.width(), - .height = mImageInfo.height(), - .color_space_ptr = mImageInfo.colorSpace(), - .clip_left = mClip.fLeft, - .clip_top = mClip.fTop, - .clip_right = mClip.fRight, - .clip_bottom = mClip.fBottom, + .width = mImageInfo.width(), + .height = mImageInfo.height(), + .color_space_ptr = mImageInfo.colorSpace(), + .clip_left = mClip.fLeft, + .clip_top = mClip.fTop, + .clip_right = mClip.fRight, + .clip_bottom = mClip.fBottom, }; mat4.asColMajorf(¶ms.transform[0]); params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer; @@ -87,8 +87,7 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) { vulkan_info.fDrawBounds->extent.height = mClip.fBottom - mClip.fTop; } -VkFunctorDrawable::~VkFunctorDrawable() { -} +VkFunctorDrawable::~VkFunctorDrawable() {} void VkFunctorDrawable::onDraw(SkCanvas* canvas) { // "canvas" is either SkNWayCanvas created by SkiaPipeline::tryCapture (SKP capture use case) or @@ -106,9 +105,8 @@ void VkFunctorDrawable::onDraw(SkCanvas* canvas) { SkCanvas* gpuCanvas = SkAndroidFrameworkUtils::getBaseWrappedCanvas(canvas); // Enforce "canvas" must be an AlphaFilterCanvas. For GPU canvas, the call should come from // onSnapGpuDrawHandler. - LOG_ALWAYS_FATAL_IF( - gpuCanvas == canvas, - "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!"); + LOG_ALWAYS_FATAL_IF(gpuCanvas == canvas, + "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!"); // This will invoke onSnapGpuDrawHandler and regular draw flow. gpuCanvas->drawDrawable(this); diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 8b02c11911ca..a31081c9a451 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -21,17 +21,16 @@ #include "RenderThread.h" #include "pipeline/skia/ShaderCache.h" #include "pipeline/skia/SkiaMemoryTracer.h" -#include "Properties.h" #include "renderstate/RenderState.h" #include "thread/CommonPool.h" #include <GrContextOptions.h> #include <SkExecutor.h> #include <SkGraphics.h> +#include <SkMathPriv.h> #include <gui/Surface.h> #include <math.h> #include <set> -#include <SkMathPriv.h> namespace android { namespace uirenderer { @@ -79,14 +78,13 @@ void CacheManager::updateContextCacheSizes() { class CommonPoolExecutor : public SkExecutor { public: - virtual void add(std::function<void(void)> func) override { - CommonPool::post(std::move(func)); - } + virtual void add(std::function<void(void)> func) override { CommonPool::post(std::move(func)); } }; static CommonPoolExecutor sDefaultExecutor; -void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) { +void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, + ssize_t size) { contextOptions->fAllowPathMaskCaching = true; // This sets the maximum size for a single texture atlas in the GPU font cache. If necessary, @@ -180,7 +178,8 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) } const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL - ? "GlLayer" : "VkLayer"; + ? "GlLayer" + : "VkLayer"; size_t layerMemoryTotal = 0; for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin(); it != renderState->mActiveLayers.end(); it++) { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 4808d68b89ab..2957b143a343 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -17,6 +17,7 @@ #include "CanvasContext.h" #include <GpuMemoryTracker.h> +#include "../Properties.h" #include "AnimationContext.h" #include "EglManager.h" #include "Frame.h" @@ -31,7 +32,6 @@ #include "utils/GLUtils.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" -#include "../Properties.h" #include <cutils/properties.h> #include <private/hwui/DrawGlInfo.h> @@ -41,6 +41,7 @@ #include <sys/stat.h> #include <algorithm> +#include <cstdint> #include <cstdlib> #include <functional> @@ -153,7 +154,8 @@ void CanvasContext::setSurface(sp<Surface>&& surface) { } ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; - bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); + bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode, + mRenderAheadDepth); mFrameNumber = -1; @@ -298,7 +300,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy mAnimationContext->startFrame(info.mode); mRenderPipeline->onPrepareTree(); - for (const sp<RenderNode> &node : mRenderNodes) { + for (const sp<RenderNode>& node : mRenderNodes) { // Only the primary target node will be drawn full - all other nodes would get drawn in // real time mode. In case of a window, the primary node is the window content and the other // node(s) are non client / filler nodes. @@ -322,7 +324,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) { nsecs_t latestVsync = mRenderThread.timeLord().latestVsync(); - SwapHistory &lastSwap = mSwapHistory.back(); + SwapHistory& lastSwap = mSwapHistory.back(); nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync); // The slight fudge-factor is to deal with cases where // the vsync was estimated due to being slow handling the signal. @@ -405,8 +407,7 @@ void CanvasContext::draw() { SkRect dirty; mDamageAccumulator.finish(&dirty); - if (dirty.isEmpty() && Properties::skipEmptyFrames - && !surfaceRequiresRedraw()) { + if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); return; } @@ -416,21 +417,21 @@ void CanvasContext::draw() { Frame frame = mRenderPipeline->getFrame(); SkRect windowDirty = computeDirtyRect(frame, &dirty); + if (mRenderAheadDepth) { + auto presentTime = + mCurrentFrameInfo->get(FrameInfoIndex::Vsync) + + (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1)); + native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime); + } bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, - mContentDrawBounds, mOpaque, mLightInfo, - mRenderNodes, &(profiler())); + mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, + &(profiler())); int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1; waitOnFences(); - if (mRenderAheadDepth) { - auto presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) + - (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1)); - native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime); - } - bool requireSwap = false; bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap); @@ -510,6 +511,17 @@ void CanvasContext::doFrame() { prepareAndDraw(nullptr); } +SkISize CanvasContext::getNextFrameSize() const { + ReliableSurface* surface = mNativeSurface.get(); + if (surface) { + SkISize size; + surface->query(NATIVE_WINDOW_WIDTH, &size.fWidth); + surface->query(NATIVE_WINDOW_HEIGHT, &size.fHeight); + return size; + } + return {INT32_MAX, INT32_MAX}; +} + void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); @@ -645,21 +657,13 @@ bool CanvasContext::surfaceRequiresRedraw() { } void CanvasContext::applyRenderAheadSettings() { - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - // TODO: Fix SkiaVulkan's assumptions on buffer counts. And SIGBUS crashes. - mRenderAheadDepth = 0; - return; - } - if (mNativeSurface) { - native_window_set_buffer_count(mNativeSurface.get(), 3 + mRenderAheadDepth); - if (!mRenderAheadDepth) { - native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO); - } + if (mNativeSurface && !mRenderAheadDepth) { + native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO); } } -void CanvasContext::setRenderAheadDepth(int renderAhead) { - if (renderAhead < 0 || renderAhead > 2 || renderAhead == mRenderAheadDepth) { +void CanvasContext::setRenderAheadDepth(uint32_t renderAhead) { + if (renderAhead > 2 || renderAhead == mRenderAheadDepth || mNativeSurface) { return; } mRenderAheadDepth = renderAhead; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 4a3119a55c77..912b1257de7b 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -17,30 +17,31 @@ #pragma once #include "DamageAccumulator.h" -#include "Lighting.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" #include "IContextFactory.h" #include "IRenderPipeline.h" #include "LayerUpdateQueue.h" -#include "RenderNode.h" +#include "Lighting.h" #include "ReliableSurface.h" +#include "RenderNode.h" #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" #include <EGL/egl.h> #include <SkBitmap.h> #include <SkRect.h> +#include <SkSize.h> #include <cutils/compiler.h> #include <gui/Surface.h> #include <utils/Functor.h> #include <functional> +#include <future> #include <set> #include <string> #include <vector> -#include <future> namespace android { namespace uirenderer { @@ -112,7 +113,7 @@ public: void setSurface(sp<Surface>&& surface); bool pauseSurface(); void setStopped(bool stopped); - bool hasSurface() { return mNativeSurface.get(); } + bool hasSurface() const { return mNativeSurface.get(); } void allocateBuffers(); void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); @@ -187,9 +188,7 @@ public: mRenderPipeline->setPictureCapturedCallback(callback); } - void setForceDark(bool enable) { - mUseForceDark = enable; - } + void setForceDark(bool enable) { mUseForceDark = enable; } bool useForceDark() { // The force-dark override has the highest priority, followed by the disable setting @@ -204,7 +203,10 @@ public: return mUseForceDark; } - void setRenderAheadDepth(int renderAhead); + // Must be called before setSurface + void setRenderAheadDepth(uint32_t renderAhead); + + SkISize getNextFrameSize() const; private: CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, @@ -238,7 +240,7 @@ private: // painted onto its surface. bool mIsDirty = false; SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default; - int mRenderAheadDepth = 0; + uint32_t mRenderAheadDepth = 0; struct SwapHistory { SkRect damage; nsecs_t vsyncTime; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 51eeab7e46ce..91dc3bc6e603 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -109,9 +109,8 @@ void DrawFrameTask::run() { // Even if we aren't drawing this vsync pulse the next frame number will still be accurate if (CC_UNLIKELY(callback)) { - context->enqueueFrameWork([callback, frameNr = context->getFrameNumber()]() { - callback(frameNr); - }); + context->enqueueFrameWork( + [callback, frameNr = context->getFrameNumber()]() { callback(frameNr); }); } if (CC_LIKELY(canDrawThisFrame)) { diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 2cc3f362e172..1d553342415c 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -29,10 +29,10 @@ #include <EGL/eglext.h> #include <GLES/gl.h> +#include <gui/Surface.h> +#include <system/window.h> #include <string> #include <vector> -#include <system/window.h> -#include <gui/Surface.h> #define GLES_VERSION 2 @@ -171,8 +171,7 @@ EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavi EGL_NONE}; EGLConfig config = EGL_NO_CONFIG_KHR; EGLint numConfigs = 1; - if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || - numConfigs != 1) { + if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) { return EGL_NO_CONFIG_KHR; } return config; @@ -203,8 +202,7 @@ EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavi EGL_NONE}; EGLConfig config = EGL_NO_CONFIG_KHR; EGLint numConfigs = 1; - if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || - numConfigs != 1) { + if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) { return EGL_NO_CONFIG_KHR; } return config; @@ -262,7 +260,7 @@ void EglManager::loadConfigs() { mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior); if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) { ALOGE("Device claims wide gamut support, cannot find matching config, error = %s", - eglErrorString()); + eglErrorString()); EglExtensions.pixelFormatFloat = false; } } else if (wideColorType == SkColorType::kN32_SkColorType) { @@ -350,7 +348,7 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window, EGLSurface surface = eglCreateWindowSurface( mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs); if (surface == EGL_NO_SURFACE) { - return Error<EGLint> { eglGetError() }; + return Error<EGLint>{eglGetError()}; } if (mSwapBehavior != SwapBehavior::Preserved) { @@ -525,12 +523,8 @@ status_t EglManager::fenceWait(sp<Fence>& fence) { ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno); return -errno; } - EGLint attribs[] = { - EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, - EGL_NONE - }; - EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, - EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE}; + EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (sync == EGL_NO_SYNC_KHR) { close(fenceFd); ALOGE("EglManager::fenceWait: error creating EGL fence: %#x", eglGetError()); @@ -559,18 +553,16 @@ status_t EglManager::fenceWait(sp<Fence>& fence) { } status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, - sp<Fence>& nativeFence) { + sp<Fence>& nativeFence) { if (!hasEglContext()) { ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized"); return INVALID_OPERATION; } if (SyncFeatures::getInstance().useNativeFenceSync()) { - EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, - EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); if (sync == EGL_NO_SYNC_KHR) { - ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x", - eglGetError()); + ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } glFlush(); @@ -578,7 +570,8 @@ status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, eglDestroySyncKHR(mEglDisplay, sync); if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { ALOGE("EglManager::createReleaseFence: error dup'ing native fence " - "fd: %#x", eglGetError()); + "fd: %#x", + eglGetError()); return UNKNOWN_ERROR; } nativeFence = new Fence(fenceFd); @@ -592,7 +585,7 @@ status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, EGLint result = eglClientWaitSyncKHR(mEglDisplay, *eglFence, 0, 1000000000); if (result == EGL_FALSE) { ALOGE("EglManager::createReleaseFence: error waiting for previous fence: %#x", - eglGetError()); + eglGetError()); return UNKNOWN_ERROR; } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { ALOGE("EglManager::createReleaseFence: timeout waiting for previous fence"); diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 0502eb88b6a5..3b81014c05e2 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -66,8 +66,8 @@ public: virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) = 0; virtual DeferredLayerUpdater* createTextureLayer() = 0; - virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, - ColorMode colorMode) = 0; + virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode, + uint32_t extraBuffers) = 0; virtual void onStop() = 0; virtual bool isSurfaceReady() = 0; virtual bool isContextReady() = 0; diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index 6f2b9df918e3..ad1fc4921781 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -34,13 +34,13 @@ struct SurfaceExposer : Surface { // Make warnings happy SurfaceExposer() = delete; - using Surface::setBufferCount; - using Surface::setSwapInterval; - using Surface::dequeueBuffer; - using Surface::queueBuffer; using Surface::cancelBuffer; + using Surface::dequeueBuffer; using Surface::lockBuffer_DEPRECATED; using Surface::perform; + using Surface::queueBuffer; + using Surface::setBufferCount; + using Surface::setSwapInterval; }; #define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__) @@ -300,17 +300,9 @@ int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) { int result = callProtected(getWrapped(window), perform, operation, args); va_end(args); - switch (operation) { - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - case NATIVE_WINDOW_SET_USAGE: - case NATIVE_WINDOW_SET_USAGE64: - va_start(args, operation); - getSelf(window)->perform(operation, args); - va_end(args); - break; - default: - break; - } + va_start(args, operation); + getSelf(window)->perform(operation, args); + va_end(args); return result; } diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index b58bab1191ed..1a1b9dac37f6 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -84,7 +84,7 @@ void RenderProxy::setName(const char* name) { void RenderProxy::setSurface(const sp<Surface>& surface) { mRenderThread.queue().post( - [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); }); + [this, surf = surface]() mutable { mContext->setSurface(std::move(surf)); }); } void RenderProxy::allocateBuffers() { @@ -251,7 +251,7 @@ void RenderProxy::dumpGraphicsMemory(int fd) { void RenderProxy::setProcessStatsBuffer(int fd) { auto& rt = RenderThread::getInstance(); - rt.queue().post([&rt, fd = dup(fd) ]() { + rt.queue().post([&rt, fd = dup(fd)]() { rt.globalProfileData().switchStorageToAshmem(fd); close(fd); }); @@ -285,7 +285,7 @@ void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) void RenderProxy::setPictureCapturedCallback( const std::function<void(sk_sp<SkPicture>&&)>& callback) { mRenderThread.queue().post( - [ this, cb = callback ]() { mContext->setPictureCapturedCallback(cb); }); + [this, cb = callback]() { mContext->setPictureCapturedCallback(cb); }); } void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) { @@ -297,13 +297,13 @@ void RenderProxy::setFrameCompleteCallback(std::function<void(int64_t)>&& callba } void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) { - mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() { + mRenderThread.queue().post([this, observer = sp{observerPtr}]() { mContext->addFrameMetricsObserver(observer.get()); }); } void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) { - mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() { + mRenderThread.queue().post([this, observer = sp{observerPtr}]() { mContext->removeFrameMetricsObserver(observer.get()); }); } @@ -313,9 +313,8 @@ void RenderProxy::setForceDark(bool enable) { } void RenderProxy::setRenderAheadDepth(int renderAhead) { - mRenderThread.queue().post([ context = mContext, renderAhead ] { - context->setRenderAheadDepth(renderAhead); - }); + mRenderThread.queue().post( + [context = mContext, renderAhead] { context->setRenderAheadDepth(renderAhead); }); } int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom, @@ -393,9 +392,7 @@ void RenderProxy::releaseVDAtlasEntries() { void RenderProxy::preload() { // Create RenderThread object and start the thread. Then preload Vulkan/EGL driver. auto& thread = RenderThread::getInstance(); - thread.queue().post([&thread]() { - thread.preload(); - }); + thread.queue().post([&thread]() { thread.preload(); }); } } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index b76e49ce94a0..eca7d88e4e48 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -16,6 +16,7 @@ #include "RenderThread.h" +#include "../HardwareBitmapUploader.h" #include "CanvasContext.h" #include "DeviceInfo.h" #include "EglManager.h" @@ -29,7 +30,6 @@ #include "utils/FatVector.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" -#include "../HardwareBitmapUploader.h" #ifdef HWUI_GLES_WRAP_ENABLED #include "debug/GlesDriver.h" @@ -410,9 +410,7 @@ bool RenderThread::isCurrent() { void RenderThread::preload() { // EGL driver is always preloaded only if HWUI renders with GL. if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { - std::thread eglInitThread([]() { - eglGetDisplay(EGL_DEFAULT_DISPLAY); - }); + std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); }); eglInitThread.detach(); } else { requireVkContext(); diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 5f43b488bcf2..6bb26fd6c675 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -22,8 +22,8 @@ #include "../JankTracker.h" #include "CacheManager.h" #include "TimeLord.h" -#include "thread/ThreadBase.h" #include "WebViewFunctorManager.h" +#include "thread/ThreadBase.h" #include "utils/TimeUtils.h" #include <GrContext.h> diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 4011329fa2da..5edf3301b2e8 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -29,7 +29,6 @@ #include <GrBackendSurface.h> #include <GrContext.h> #include <GrTypes.h> -#include <GrTypes.h> #include <vk/GrVkExtensions.h> #include <vk/GrVkTypes.h> @@ -43,7 +42,7 @@ static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& fe // so we can get access to the pNext for the next struct. struct CommonVulkanHeader { VkStructureType sType; - void* pNext; + void* pNext; }; void* pNext = features.pNext; @@ -94,13 +93,13 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe VkResult err; constexpr VkApplicationInfo app_info = { - VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType - nullptr, // pNext - "android framework", // pApplicationName - 0, // applicationVersion - "android framework", // pEngineName - 0, // engineVerison - mAPIVersion, // apiVersion + VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType + nullptr, // pNext + "android framework", // pApplicationName + 0, // applicationVersion + "android framework", // pEngineName + 0, // engineVerison + mAPIVersion, // apiVersion }; { @@ -128,14 +127,14 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe } const VkInstanceCreateInfo instance_create = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType - nullptr, // pNext - 0, // flags - &app_info, // pApplicationInfo - 0, // enabledLayerNameCount - nullptr, // ppEnabledLayerNames - (uint32_t) mInstanceExtensions.size(), // enabledExtensionNameCount - mInstanceExtensions.data(), // ppEnabledExtensionNames + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags + &app_info, // pApplicationInfo + 0, // enabledLayerNameCount + nullptr, // ppEnabledLayerNames + (uint32_t)mInstanceExtensions.size(), // enabledExtensionNameCount + mInstanceExtensions.data(), // ppEnabledExtensionNames }; GET_PROC(CreateInstance); @@ -200,11 +199,11 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe { uint32_t extensionCount = 0; err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount, - nullptr); + nullptr); LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err); mDeviceExtensionsOwner.resize(extensionCount); err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount, - mDeviceExtensionsOwner.data()); + mDeviceExtensionsOwner.data()); LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err); bool hasKHRSwapchainExtension = false; for (const VkExtensionProperties& extension : mDeviceExtensionsOwner) { @@ -216,7 +215,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe LOG_ALWAYS_FATAL_IF(!hasKHRSwapchainExtension); } - auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) { + auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) { if (device != VK_NULL_HANDLE) { return vkGetDeviceProcAddr(device, proc_name); } @@ -224,7 +223,8 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe }; grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(), - mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data()); + mInstanceExtensions.data(), mDeviceExtensions.size(), + mDeviceExtensions.data()); LOG_ALWAYS_FATAL_IF(!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)); @@ -237,7 +237,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe if (grExtensions.hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2)) { VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT* blend; - blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*) malloc( + blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*)malloc( sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT)); LOG_ALWAYS_FATAL_IF(!blend); blend->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; @@ -247,7 +247,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe } VkPhysicalDeviceSamplerYcbcrConversionFeatures* ycbcrFeature; - ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*) malloc( + ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)malloc( sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures)); LOG_ALWAYS_FATAL_IF(!ycbcrFeature); ycbcrFeature->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; @@ -261,17 +261,17 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe // and we can't depend on it on all platforms features.features.robustBufferAccess = VK_FALSE; - float queuePriorities[1] = { 0.0 }; + float queuePriorities[1] = {0.0}; void* queueNextPtr = nullptr; VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo; - if (Properties::contextPriority != 0 - && grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) { + if (Properties::contextPriority != 0 && + grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) { memset(&queuePriorityCreateInfo, 0, sizeof(VkDeviceQueueGlobalPriorityCreateInfoEXT)); queuePriorityCreateInfo.sType = - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT; + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT; queuePriorityCreateInfo.pNext = nullptr; switch (Properties::contextPriority) { case EGL_CONTEXT_PRIORITY_LOW_IMG: @@ -285,41 +285,40 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe break; default: LOG_ALWAYS_FATAL("Unsupported context priority"); - } - queueNextPtr = &queuePriorityCreateInfo; + } + queueNextPtr = &queuePriorityCreateInfo; } const VkDeviceQueueCreateInfo queueInfo[2] = { - { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType - queueNextPtr, // pNext - 0, // VkDeviceQueueCreateFlags - mGraphicsQueueIndex, // queueFamilyIndex - 1, // queueCount - queuePriorities, // pQueuePriorities - }, - { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType - queueNextPtr, // pNext - 0, // VkDeviceQueueCreateFlags - mPresentQueueIndex, // queueFamilyIndex - 1, // queueCount - queuePriorities, // pQueuePriorities - } - }; + { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType + queueNextPtr, // pNext + 0, // VkDeviceQueueCreateFlags + mGraphicsQueueIndex, // queueFamilyIndex + 1, // queueCount + queuePriorities, // pQueuePriorities + }, + { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType + queueNextPtr, // pNext + 0, // VkDeviceQueueCreateFlags + mPresentQueueIndex, // queueFamilyIndex + 1, // queueCount + queuePriorities, // pQueuePriorities + }}; uint32_t queueInfoCount = (mPresentQueueIndex != mGraphicsQueueIndex) ? 2 : 1; const VkDeviceCreateInfo deviceInfo = { - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType - &features, // pNext - 0, // VkDeviceCreateFlags - queueInfoCount, // queueCreateInfoCount - queueInfo, // pQueueCreateInfos - 0, // layerCount - nullptr, // ppEnabledLayerNames - (uint32_t) mDeviceExtensions.size(), // extensionCount - mDeviceExtensions.data(), // ppEnabledExtensionNames - nullptr, // ppEnabledFeatures + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType + &features, // pNext + 0, // VkDeviceCreateFlags + queueInfoCount, // queueCreateInfoCount + queueInfo, // pQueueCreateInfos + 0, // layerCount + nullptr, // ppEnabledLayerNames + (uint32_t)mDeviceExtensions.size(), // extensionCount + mDeviceExtensions.data(), // ppEnabledExtensionNames + nullptr, // ppEnabledFeatures }; LOG_ALWAYS_FATAL_IF(mCreateDevice(mPhysicalDevice, &deviceInfo, nullptr, &mDevice)); @@ -371,8 +370,8 @@ void VulkanManager::initialize() { // this needs to be on the render queue commandPoolInfo.queueFamilyIndex = mGraphicsQueueIndex; commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - SkDEBUGCODE(VkResult res =) mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, - &mCommandPool); + SkDEBUGCODE(VkResult res =) + mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, &mCommandPool); SkASSERT(VK_SUCCESS == res); } LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE); @@ -391,7 +390,7 @@ void VulkanManager::initialize() { } sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) { - auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) { + auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) { if (device != VK_NULL_HANDLE) { return vkGetDeviceProcAddr(device, proc_name); } @@ -431,7 +430,6 @@ VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const { } Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) { - VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer(); if (bufferInfo == nullptr) { @@ -480,7 +478,7 @@ Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) { bufferInfo->skSurface->wait(1, &backendSemaphore); // The following flush blocks the GPU immediately instead of waiting for other // drawing ops. It seems dequeue_fence is not respected otherwise. - //TODO: remove the flush after finding why backendSemaphore is not working. + // TODO: remove the flush after finding why backendSemaphore is not working. bufferInfo->skSurface->flush(); } } @@ -557,15 +555,15 @@ void VulkanManager::destroySurface(VulkanSurface* surface) { VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode, sk_sp<SkColorSpace> surfaceColorSpace, - SkColorType surfaceColorType, - GrContext* grContext) { + SkColorType surfaceColorType, GrContext* grContext, + uint32_t extraBuffers) { LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized"); if (!window) { return nullptr; } return VulkanSurface::Create(window, colorMode, surfaceColorType, surfaceColorSpace, grContext, - *this); + *this, extraBuffers); } bool VulkanManager::setupDummyCommandBuffer() { diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index a7a43cc39a45..1a3a0e485523 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -18,16 +18,16 @@ #define VULKANMANAGER_H #if !defined(VK_USE_PLATFORM_ANDROID_KHR) -# define VK_USE_PLATFORM_ANDROID_KHR +#define VK_USE_PLATFORM_ANDROID_KHR #endif #include <vulkan/vulkan.h> #include <GrContextOptions.h> -#include <vk/GrVkExtensions.h> #include <SkSurface.h> #include <ui/Fence.h> #include <utils/StrongPointer.h> #include <vk/GrVkBackendContext.h> +#include <vk/GrVkExtensions.h> #include "Frame.h" #include "IRenderPipeline.h" #include "VulkanSurface.h" @@ -59,8 +59,8 @@ public: // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode, sk_sp<SkColorSpace> surfaceColorSpace, - SkColorType surfaceColorType, - GrContext* grContext); + SkColorType surfaceColorType, GrContext* grContext, + uint32_t extraBuffers); void destroySurface(VulkanSurface* surface); Frame dequeueNextBuffer(VulkanSurface* surface); diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index be78b694f53a..df6b9ed2cdcb 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -16,12 +16,12 @@ #include "VulkanSurface.h" -#include <algorithm> #include <SkSurface.h> +#include <algorithm> #include "VulkanManager.h" -#include "utils/TraceUtils.h" #include "utils/Color.h" +#include "utils/TraceUtils.h" namespace android { namespace uirenderer { @@ -31,10 +31,9 @@ static bool IsTransformSupported(int transform) { // For now, only support pure rotations, not flip or flip-and-rotate, until we have // more time to test them and build sample code. As far as I know we never actually // use anything besides pure rotations anyway. - return transform == 0 - || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 - || transform == NATIVE_WINDOW_TRANSFORM_ROT_180 - || transform == NATIVE_WINDOW_TRANSFORM_ROT_270; + return transform == 0 || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 || + transform == NATIVE_WINDOW_TRANSFORM_ROT_180 || + transform == NATIVE_WINDOW_TRANSFORM_ROT_270; } static int InvertTransform(int transform) { @@ -85,16 +84,16 @@ static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) { } void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize, - const SkISize& maxSize) { + const SkISize& maxSize) { SkISize& windowSize = windowInfo->size; // clamp width & height to handle currentExtent of -1 and protect us from broken hints - if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() - || windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) { + if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() || + windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) { int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width())); int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height())); - ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", - windowSize.width(), windowSize.height(), width, height); + ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", windowSize.width(), + windowSize.height(), width, height); windowSize.set(width, height); } @@ -145,12 +144,8 @@ class VkSurfaceAutoDeleter { public: VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface, PFN_vkDestroySurfaceKHR destroySurfaceKHR) - : mInstance(instance) - , mSurface(surface) - , mDestroySurfaceKHR(destroySurfaceKHR) {} - ~VkSurfaceAutoDeleter() { - destroy(); - } + : mInstance(instance), mSurface(surface), mDestroySurfaceKHR(destroySurfaceKHR) {} + ~VkSurfaceAutoDeleter() { destroy(); } void destroy() { if (mSurface != VK_NULL_HANDLE) { @@ -166,9 +161,9 @@ private: }; VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, - SkColorType colorType, sk_sp<SkColorSpace> colorSpace, - GrContext* grContext, const VulkanManager& vkManager) { - + SkColorType colorType, sk_sp<SkColorSpace> colorSpace, + GrContext* grContext, const VulkanManager& vkManager, + uint32_t extraBuffers) { VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR)); surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; @@ -188,10 +183,11 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, vkManager.mDestroySurfaceKHR); SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR( - vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, vkSurface, &supported); - // All physical devices and queue families on Android must be capable of - // presentation with any native window. - SkASSERT(VK_SUCCESS == res && supported);); + vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, + vkSurface, &supported); + // All physical devices and queue families on Android must be capable of + // presentation with any native window. + SkASSERT(VK_SUCCESS == res && supported);); // check for capabilities VkSurfaceCapabilitiesKHR caps; @@ -225,14 +221,13 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, int query_value; int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); if (err != 0 || query_value < 0) { - ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, - query_value); + ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); return nullptr; } auto min_undequeued_buffers = static_cast<uint32_t>(query_value); - windowInfo.bufferCount = min_undequeued_buffers - + std::max(VulkanSurface::sTargetBufferCount, caps.minImageCount); + windowInfo.bufferCount = min_undequeued_buffers + + std::max(sTargetBufferCount + extraBuffers, caps.minImageCount); if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) { // Application must settle for fewer images than desired: windowInfo.bufferCount = caps.maxImageCount; @@ -241,8 +236,7 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, // Currently Skia requires the images to be color attachments and support all transfer // operations. VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags); @@ -336,7 +330,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_buffers_data_space(window, windowInfo.dataspace); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) " - "failed: %s (%d)", windowInfo.dataspace, strerror(-err), err); + "failed: %s (%d)", + windowInfo.dataspace, strerror(-err), err); return false; } @@ -344,7 +339,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_buffers_dimensions(window, size.width(), size.height()); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) " - "failed: %s (%d)", size.width(), size.height(), strerror(-err), err); + "failed: %s (%d)", + size.width(), size.height(), strerror(-err), err); return false; } @@ -357,7 +353,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform)); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) " - "failed: %s (%d)", windowInfo.transform, strerror(-err), err); + "failed: %s (%d)", + windowInfo.transform, strerror(-err), err); return false; } @@ -366,7 +363,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) " - "failed: %s (%d)", strerror(-err), err); + "failed: %s (%d)", + strerror(-err), err); return false; } @@ -388,12 +386,12 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window } VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, - SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext) + SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext) : mNativeWindow(window) , mWindowInfo(windowInfo) , mGrContext(grContext) , mMinWindowSize(minWindowSize) - , mMaxWindowSize(maxWindowSize) { } + , mMaxWindowSize(maxWindowSize) {} VulkanSurface::~VulkanSurface() { releaseBuffers(); @@ -436,8 +434,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { // value at the end of the function if everything dequeued correctly. mCurrentBufferInfo = nullptr; - - //check if the native window has been resized or rotated and update accordingly + // check if the native window has been resized or rotated and update accordingly SkISize newSize = SkISize::MakeEmpty(); int transformHint = 0; mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth); @@ -457,8 +454,8 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { newWindowInfo.actualSize.height()); if (err != 0) { ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", - newWindowInfo.actualSize.width(), - newWindowInfo.actualSize.height(), strerror(-err), err); + newWindowInfo.actualSize.width(), newWindowInfo.actualSize.height(), + strerror(-err), err); return nullptr; } // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The @@ -469,7 +466,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { if (newWindowInfo.transform != mWindowInfo.transform) { err = native_window_set_buffers_transform(mNativeWindow.get(), - InvertTransform(newWindowInfo.transform)); + InvertTransform(newWindowInfo.transform)); if (err != 0) { ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", newWindowInfo.transform, strerror(-err), err); @@ -512,11 +509,9 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx]; if (bufferInfo->skSurface.get() == nullptr) { - bufferInfo->skSurface = - SkSurface::MakeFromAHardwareBuffer(mGrContext, - ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()), - kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), - nullptr); + bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer( + mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()), + kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr); if (bufferInfo->skSurface.get() == nullptr) { ALOGE("SkSurface::MakeFromAHardwareBuffer failed"); mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd); @@ -530,19 +525,19 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) { if (!dirtyRect.isEmpty()) { - SkRect transformedRect; - mWindowInfo.preTransform.mapRect(&transformedRect, dirtyRect); - SkIRect transformedIRect; - transformedRect.roundOut(&transformedIRect); - transformedIRect.intersect(0, 0, mWindowInfo.size.fWidth, mWindowInfo.size.fHeight); + // native_window_set_surface_damage takes a rectangle in prerotated space + // with a bottom-left origin. That is, top > bottom. + // The dirtyRect is also in prerotated space, so we just need to switch it to + // a bottom-left origin space. - // map to bottom-left coordinate system + SkIRect irect; + dirtyRect.roundOut(&irect); android_native_rect_t aRect; - aRect.left = transformedIRect.x(); - aRect.top = mWindowInfo.size.fHeight - (transformedIRect.y() + transformedIRect.height()); - aRect.right = aRect.left + transformedIRect.width(); - aRect.bottom = aRect.top - transformedIRect.height(); + aRect.left = irect.left(); + aRect.top = logicalHeight() - irect.top(); + aRect.right = irect.right(); + aRect.bottom = logicalHeight() - irect.bottom(); int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1); ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err); diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h index 305483fce2d5..b7af596ae762 100644 --- a/libs/hwui/renderthread/VulkanSurface.h +++ b/libs/hwui/renderthread/VulkanSurface.h @@ -19,8 +19,8 @@ #include <system/window.h> #include <vulkan/vulkan.h> -#include <SkSize.h> #include <SkRefCnt.h> +#include <SkSize.h> #include "IRenderPipeline.h" @@ -34,12 +34,9 @@ class VulkanManager; class VulkanSurface { public: - static VulkanSurface* Create(ANativeWindow* window, - ColorMode colorMode, - SkColorType colorType, - sk_sp<SkColorSpace> colorSpace, - GrContext* grContext, - const VulkanManager& vkManager); + static VulkanSurface* Create(ANativeWindow* window, ColorMode colorMode, SkColorType colorType, + sk_sp<SkColorSpace> colorSpace, GrContext* grContext, + const VulkanManager& vkManager, uint32_t extraBuffers); ~VulkanSurface(); sk_sp<SkSurface> getCurrentSkSurface() { @@ -104,15 +101,10 @@ private: SkMatrix preTransform; }; - VulkanSurface(ANativeWindow* window, - const WindowInfo& windowInfo, - SkISize minWindowSize, - SkISize maxWindowSize, - GrContext* grContext); - static bool UpdateWindow(ANativeWindow* window, - const WindowInfo& windowInfo); - static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo, - const SkISize& minSize, + VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, SkISize minWindowSize, + SkISize maxWindowSize, GrContext* grContext); + static bool UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo); + static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize, const SkISize& maxSize); void releaseBuffers(); diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 1b4cf7e144bd..6fb164a99ae4 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -23,6 +23,7 @@ #include "pipeline/skia/GLFunctorDrawable.h" #include "pipeline/skia/SkiaDisplayList.h" #include "renderthread/CanvasContext.h" +#include "tests/common/TestContext.h" #include "tests/common/TestUtils.h" using namespace android; @@ -50,13 +51,13 @@ TEST(SkiaDisplayList, reset) { GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas); skiaDL->mChildFunctors.push_back(&functorDrawable); skiaDL->mMutableImages.push_back(nullptr); - skiaDL->mVectorDrawables.push_back(nullptr); + skiaDL->appendVD(nullptr); skiaDL->mProjectionReceiver = &drawable; ASSERT_FALSE(skiaDL->mChildNodes.empty()); ASSERT_FALSE(skiaDL->mChildFunctors.empty()); ASSERT_FALSE(skiaDL->mMutableImages.empty()); - ASSERT_FALSE(skiaDL->mVectorDrawables.empty()); + ASSERT_TRUE(skiaDL->hasVectorDrawables()); ASSERT_FALSE(skiaDL->isEmpty()); ASSERT_TRUE(skiaDL->mProjectionReceiver); @@ -65,7 +66,7 @@ TEST(SkiaDisplayList, reset) { ASSERT_TRUE(skiaDL->mChildNodes.empty()); ASSERT_TRUE(skiaDL->mChildFunctors.empty()); ASSERT_TRUE(skiaDL->mMutableImages.empty()); - ASSERT_TRUE(skiaDL->mVectorDrawables.empty()); + ASSERT_FALSE(skiaDL->hasVectorDrawables()); ASSERT_TRUE(skiaDL->isEmpty()); ASSERT_FALSE(skiaDL->mProjectionReceiver); } @@ -110,7 +111,7 @@ TEST(SkiaDisplayList, syncContexts) { SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); vectorDrawable.mutateStagingProperties()->setBounds(bounds); - skiaDL.mVectorDrawables.push_back(&vectorDrawable); + skiaDL.appendVD(&vectorDrawable); // ensure that the functor and vectorDrawable are properly synced TestUtils::runOnRenderThread([&](auto&) { @@ -149,9 +150,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { SkiaDisplayList skiaDL; + // The VectorDrawableRoot needs to have bounds on screen (and therefore not + // empty) in order to have PropertyChangeWillBeConsumed set. + const auto bounds = SkRect::MakeIWH(100, 100); + // prepare with a clean VD VectorDrawableRoot cleanVD(new VectorDrawable::Group()); - skiaDL.mVectorDrawables.push_back(&cleanVD); + cleanVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&cleanVD); cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit ASSERT_FALSE(cleanVD.isDirty()); @@ -159,11 +165,12 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { TestUtils::MockTreeObserver observer; ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); - ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed()); + ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed()); // prepare again this time adding a dirty VD VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); - skiaDL.mVectorDrawables.push_back(&dirtyVD); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD); ASSERT_TRUE(dirtyVD.isDirty()); ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); @@ -191,6 +198,169 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { canvasContext->destroy(); } +RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren_vdOffscreen) { + auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr); + ContextFactory contextFactory; + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory)); + + // Set up a Surface so that we can position the VectorDrawable offscreen. + test::TestContext testContext; + testContext.setRenderOffscreen(true); + auto surface = testContext.surface(); + int width, height; + surface->query(NATIVE_WINDOW_WIDTH, &width); + surface->query(NATIVE_WINDOW_HEIGHT, &height); + canvasContext->setSurface(std::move(surface)); + + TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get()); + DamageAccumulator damageAccumulator; + info.damageAccumulator = &damageAccumulator; + + // The VectorDrawableRoot needs to have bounds on screen (and therefore not + // empty) in order to have PropertyChangeWillBeConsumed set. + const auto bounds = SkRect::MakeIWH(100, 100); + + for (const SkRect b : {bounds.makeOffset(width, 0), + bounds.makeOffset(0, height), + bounds.makeOffset(-bounds.width(), 0), + bounds.makeOffset(0, -bounds.height())}) { + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(b); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + + // The DamageAccumulator's transform can also result in the + // VectorDrawableRoot being offscreen. + for (const SkISize translate : { SkISize{width, 0}, + SkISize{0, height}, + SkISize{-width, 0}, + SkISize{0, -height}}) { + Matrix4 mat4; + mat4.translate(translate.fWidth, translate.fHeight); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + + // Another way to be offscreen: a matrix from the draw call. + for (const SkMatrix translate : { SkMatrix::MakeTrans(width, 0), + SkMatrix::MakeTrans(0, height), + SkMatrix::MakeTrans(-width, 0), + SkMatrix::MakeTrans(0, -height)}) { + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD, translate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + + // Verify that the matrices are combined in the right order. + { + // Rotate and then translate, so the VD is offscreen. + Matrix4 mat4; + mat4.loadRotate(180); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix translate = SkMatrix::MakeTrans(50, 50); + skiaDL.appendVD(&dirtyVD, translate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + { + // Switch the order of rotate and translate, so it is on screen. + Matrix4 mat4; + mat4.translate(50, 50); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix rotate; + rotate.setRotate(180); + skiaDL.appendVD(&dirtyVD, rotate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + { + // An AVD that is larger than the screen. + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(SkRect::MakeLTRB(-1, -1, width + 1, height + 1)); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + { + // An AVD whose bounds are not a rectangle after applying a matrix. + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix mat; + mat.setRotate(45, 50, 50); + skiaDL.appendVD(&dirtyVD, mat); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + } +} + TEST(SkiaDisplayList, updateChildren) { SkiaDisplayList skiaDL; diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index e86cf42fee4d..a671bdada09a 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -31,6 +31,9 @@ #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" +#include <gui/BufferItemConsumer.h> +#include <gui/Surface.h> + using namespace android; using namespace android::uirenderer; using namespace android::uirenderer::renderthread; @@ -421,10 +424,20 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) { EXPECT_EQ(1, surface->canvas()->mDrawCounter); } +static sp<Surface> createDummySurface() { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + producer->setMaxDequeuedBufferCount(1); + producer->setAsyncMode(true); + return new Surface(producer); +} + RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { + auto surface = createDummySurface(); auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); EXPECT_FALSE(pipeline->isSurfaceReady()); - EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB)); + EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, ColorMode::SRGB, 0)); EXPECT_TRUE(pipeline->isSurfaceReady()); renderThread.destroyRenderingContext(); EXPECT_FALSE(pipeline->isSurfaceReady()); diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java index ce464b7bda37..211a0cb5852d 100644 --- a/location/java/android/location/GnssStatus.java +++ b/location/java/android/location/GnssStatus.java @@ -17,6 +17,7 @@ package android.location; import android.annotation.IntDef; +import android.annotation.NonNull; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -44,6 +45,8 @@ public final class GnssStatus { public static final int CONSTELLATION_GALILEO = 6; /** Constellation type constant for IRNSS. */ public static final int CONSTELLATION_IRNSS = 7; + /** @hide */ + public static final int CONSTELLATION_COUNT = 8; /** @hide */ public static final int GNSS_SV_FLAGS_NONE = 0; @@ -251,4 +254,36 @@ public final class GnssStatus { public float getCarrierFrequencyHz(int satIndex) { return mCarrierFrequencies[satIndex]; } + + /** + * Returns the string representation of a constellation type. For example, + * {@link #CONSTELLATION_GPS} is represented by the string GPS. + * + * @param constellationType the constellation type. + * @return the string representation. + * @hide + */ + @NonNull + public static String constellationTypeToString(@ConstellationType int constellationType) { + switch (constellationType) { + case CONSTELLATION_UNKNOWN: + return "UNKNOWN"; + case CONSTELLATION_GPS: + return "GPS"; + case CONSTELLATION_SBAS: + return "SBAS"; + case CONSTELLATION_GLONASS: + return "GLONASS"; + case CONSTELLATION_QZSS: + return "QZSS"; + case CONSTELLATION_BEIDOU: + return "BEIDOU"; + case CONSTELLATION_GALILEO: + return "GALILEO"; + case CONSTELLATION_IRNSS: + return "IRNSS"; + default: + return Integer.toString(constellationType); + } + } } diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java index 057a4ae879f4..78239714ca3b 100644 --- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java +++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java @@ -16,26 +16,26 @@ package com.android.internal.location.gnssmetrics; +import android.location.GnssStatus; import android.os.SystemClock; -import android.os.connectivity.GpsBatteryStats; import android.os.SystemProperties; - +import android.os.connectivity.GpsBatteryStats; import android.server.location.ServerLocationProtoEnums; - import android.text.format.DateUtils; import android.util.Base64; import android.util.Log; import android.util.StatsLog; import android.util.TimeUtils; -import java.util.Arrays; - import com.android.internal.app.IBatteryStats; import com.android.internal.location.nano.GnssLogsProto.GnssLog; import com.android.internal.location.nano.GnssLogsProto.PowerMetrics; +import java.util.Arrays; + /** * GnssMetrics: Is used for logging GNSS metrics + * * @hide */ public class GnssMetrics { @@ -66,6 +66,11 @@ public class GnssMetrics { /* GNSS power metrics */ private GnssPowerMetrics mGnssPowerMetrics; + /** + * A boolean array indicating whether the constellation types have been used in fix. + */ + private boolean[] mConstellationTypes; + /** Constructor */ public GnssMetrics(IBatteryStats stats) { mGnssPowerMetrics = new GnssPowerMetrics(stats); @@ -156,6 +161,18 @@ public class GnssMetrics { return; } + + /** + * Logs that a constellation type has been observed. + */ + public void logConstellationType(int constellationType) { + if (constellationType >= mConstellationTypes.length) { + Log.e(TAG, "Constellation type " + constellationType + " is not valid."); + return; + } + mConstellationTypes[constellationType] = true; + } + /** * Dumps GNSS metrics as a proto string * @return @@ -232,6 +249,13 @@ public class GnssMetrics { s.append(" Top 4 Avg CN0 standard deviation (dB-Hz): ").append( topFourAverageCn0Statistics.getStandardDeviation()).append("\n"); } + s.append(" Used-in-fix constellation types: "); + for (int i = 0; i < mConstellationTypes.length; i++) { + if (mConstellationTypes[i]) { + s.append(GnssStatus.constellationTypeToString(i)).append(" "); + } + } + s.append("\n"); s.append("GNSS_KPI_END").append("\n"); GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats(); if (stats != null) { @@ -320,9 +344,15 @@ public class GnssMetrics { timeToFirstFixSecStatistics.reset(); positionAccuracyMeterStatistics.reset(); topFourAverageCn0Statistics.reset(); + resetConstellationTypes(); return; } + /** Resets {@link #mConstellationTypes} as an all-false boolean array. */ + public void resetConstellationTypes() { + mConstellationTypes = new boolean[GnssStatus.CONSTELLATION_COUNT]; + } + /* Class for handling GNSS power related metrics */ private class GnssPowerMetrics { diff --git a/media/Android.bp b/media/Android.bp index 8746046c220d..5b7b26cef27a 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -64,7 +64,6 @@ filegroup { "apex/java/android/media/IMediaSession2Service.aidl", "apex/java/android/media/MediaConstants.java", "apex/java/android/media/MediaController2.java", - "apex/java/android/media/MediaItem2.java", "apex/java/android/media/MediaSession2.java", "apex/java/android/media/MediaSession2Service.java", "apex/java/android/media/Session2Command.java", diff --git a/media/apex/java/android/media/DataSourceDesc.java b/media/apex/java/android/media/DataSourceDesc.java index d00ff2a70955..9a9c74aba2c7 100644 --- a/media/apex/java/android/media/DataSourceDesc.java +++ b/media/apex/java/android/media/DataSourceDesc.java @@ -34,6 +34,8 @@ import java.util.Map; * * Used by {@link MediaPlayer2#setDataSource}, {@link MediaPlayer2#setNextDataSource} and * {@link MediaPlayer2#setNextDataSources} to set data source for playback. + * + * @hide */ public class DataSourceDesc { // intentionally less than long.MAX_VALUE diff --git a/media/apex/java/android/media/FileDataSourceDesc.java b/media/apex/java/android/media/FileDataSourceDesc.java index feb67e136d9b..2aa2cb7eb1bb 100644 --- a/media/apex/java/android/media/FileDataSourceDesc.java +++ b/media/apex/java/android/media/FileDataSourceDesc.java @@ -17,7 +17,6 @@ package android.media; import android.annotation.NonNull; -import android.annotation.TestApi; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -32,7 +31,6 @@ import java.io.IOException; * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}. * @hide */ -@TestApi public class FileDataSourceDesc extends DataSourceDesc { private static final String TAG = "FileDataSourceDesc"; diff --git a/media/apex/java/android/media/MediaConstants.java b/media/apex/java/android/media/MediaConstants.java index 776c1ba3f82f..ce108894b9a5 100644 --- a/media/apex/java/android/media/MediaConstants.java +++ b/media/apex/java/android/media/MediaConstants.java @@ -28,6 +28,7 @@ class MediaConstants { static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS"; static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE"; static final String KEY_TOKEN_EXTRAS = "android.media.key.TOKEN_EXTRAS"; + static final String KEY_CONNECTION_HINTS = "android.media.key.CONNECTION_HINTS"; private MediaConstants() { } diff --git a/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java index 1e8438ec9fe8..fb4e6ac23937 100644 --- a/media/apex/java/android/media/MediaController2.java +++ b/media/apex/java/android/media/MediaController2.java @@ -17,6 +17,7 @@ package android.media; import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; +import static android.media.MediaConstants.KEY_CONNECTION_HINTS; import static android.media.MediaConstants.KEY_PACKAGE_NAME; import static android.media.MediaConstants.KEY_PID; import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE; @@ -91,24 +92,16 @@ public class MediaController2 implements AutoCloseable { * Create a {@link MediaController2} from the {@link Session2Token}. * This connects to the session and may wake up the service if it's not available. * - * @param context Context - * @param token token to connect to - */ - public MediaController2(@NonNull Context context, @NonNull Session2Token token) { - this(context, token, context.getMainExecutor(), new ControllerCallback() {}); - } - - /** - * Create a {@link MediaController2} from the {@link Session2Token}. - * This connects to the session and may wake up the service if it's not available. - * - * @param context Context + * @param context context * @param token token to connect to + * @param connectionHints a session-specific argument to send to the session when connecting. + * The contents of this bundle may affect the connection result. * @param executor executor to run callbacks on. * @param callback controller callback to receive changes in. */ - public MediaController2(@NonNull Context context, @NonNull Session2Token token, - @NonNull Executor executor, @NonNull ControllerCallback callback) { + MediaController2(@NonNull Context context, @NonNull Session2Token token, + @Nullable Bundle connectionHints, @NonNull Executor executor, + @NonNull ControllerCallback callback) { if (context == null) { throw new IllegalArgumentException("context shouldn't be null"); } @@ -130,9 +123,9 @@ public class MediaController2 implements AutoCloseable { boolean connectRequested; if (token.getType() == TYPE_SESSION) { mServiceConnection = null; - connectRequested = requestConnectToSession(); + connectRequested = requestConnectToSession(connectionHints); } else { - mServiceConnection = new SessionServiceConnection(); + mServiceConnection = new SessionServiceConnection(connectionHints); connectRequested = requestConnectToService(); } if (!connectRequested) { @@ -350,16 +343,17 @@ public class MediaController2 implements AutoCloseable { } } - private Bundle createConnectionRequest() { + private Bundle createConnectionRequest(@Nullable Bundle connectionHints) { Bundle connectionRequest = new Bundle(); connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName()); connectionRequest.putInt(KEY_PID, Process.myPid()); + connectionRequest.putBundle(KEY_CONNECTION_HINTS, connectionHints); return connectionRequest; } - private boolean requestConnectToSession() { + private boolean requestConnectToSession(@Nullable Bundle connectionHints) { Session2Link sessionBinder = mSessionToken.getSessionLink(); - Bundle connectionRequest = createConnectionRequest(); + Bundle connectionRequest = createConnectionRequest(connectionHints); try { sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest); } catch (RuntimeException e) { @@ -402,6 +396,93 @@ public class MediaController2 implements AutoCloseable { } /** + * Builder for {@link MediaController2}. + * <p> + * Any incoming event from the {@link MediaSession2} will be handled on the callback + * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default. + */ + public static final class Builder { + private Context mContext; + private Session2Token mToken; + private Bundle mConnectionHints; + private Executor mCallbackExecutor; + private ControllerCallback mCallback; + + /** + * Creates a builder for {@link MediaController2}. + * + * @param context context + * @param token token of the session to connect to + */ + public Builder(@NonNull Context context, @NonNull Session2Token token) { + if (context == null) { + throw new IllegalArgumentException("context shouldn't be null"); + } + if (token == null) { + throw new IllegalArgumentException("token shouldn't be null"); + } + mContext = context; + mToken = token; + } + + /** + * Set the connection hints for the controller. + * <p> + * {@code connectionHints} is a session-specific argument to send to the session when + * connecting. The contents of this bundle may affect the connection result. + * + * @param connectionHints a bundle which contains the connection hints + * @return The Builder to allow chaining + */ + @NonNull + public Builder setConnectionHints(@NonNull Bundle connectionHints) { + if (connectionHints == null) { + throw new IllegalArgumentException("connectionHints shouldn't be null"); + } + mConnectionHints = new Bundle(connectionHints); + return this; + } + + /** + * Set callback for the controller and its executor. + * + * @param executor callback executor + * @param callback session callback. + * @return The Builder to allow chaining + */ + @NonNull + public Builder setControllerCallback(@NonNull Executor executor, + @NonNull ControllerCallback callback) { + if (executor == null) { + throw new IllegalArgumentException("executor shouldn't be null"); + } + if (callback == null) { + throw new IllegalArgumentException("callback shouldn't be null"); + } + mCallbackExecutor = executor; + mCallback = callback; + return this; + } + + /** + * Build {@link MediaController2}. + * + * @return a new controller + */ + @NonNull + public MediaController2 build() { + if (mCallbackExecutor == null) { + mCallbackExecutor = mContext.getMainExecutor(); + } + if (mCallback == null) { + mCallback = new ControllerCallback() {}; + } + return new MediaController2( + mContext, mToken, mConnectionHints, mCallbackExecutor, mCallback); + } + } + + /** * Interface for listening to change in activeness of the {@link MediaSession2}. * <p> * This API is not generally intended for third party application developers. @@ -469,7 +550,10 @@ public class MediaController2 implements AutoCloseable { // This will be called on the main thread. private class SessionServiceConnection implements ServiceConnection { - SessionServiceConnection() { + private final Bundle mConnectionHints; + + SessionServiceConnection(@Nullable Bundle connectionHints) { + mConnectionHints = connectionHints; } @Override @@ -491,7 +575,7 @@ public class MediaController2 implements AutoCloseable { Log.wtf(TAG, "Service interface is missing."); return; } - Bundle connectionRequest = createConnectionRequest(); + Bundle connectionRequest = createConnectionRequest(mConnectionHints); iService.connect(mControllerStub, getNextSeqNumber(), connectionRequest); connectRequested = true; } catch (RemoteException e) { diff --git a/media/apex/java/android/media/MediaItem2.java b/media/apex/java/android/media/MediaItem2.java deleted file mode 100644 index ff0d43e41350..000000000000 --- a/media/apex/java/android/media/MediaItem2.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -import static android.media.MediaMetadata.METADATA_KEY_MEDIA_ID; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; - -import com.android.internal.annotations.GuardedBy; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; - -/** - * A class with information on a single media item with the metadata information. - * <p> - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a> - * for consistent behavior across all devices. - * <p> - */ -public final class MediaItem2 implements Parcelable { - private static final String TAG = "MediaItem2"; - - // intentionally less than long.MAX_VALUE. - // Declare this first to avoid 'illegal forward reference'. - static final long LONG_MAX = 0x7ffffffffffffffL; - - /** - * Used when a position is unknown. - * - * @see #getEndPosition() - */ - public static final long POSITION_UNKNOWN = LONG_MAX; - - public static final @android.annotation.NonNull Parcelable.Creator<MediaItem2> CREATOR = - new Parcelable.Creator<MediaItem2>() { - @Override - public MediaItem2 createFromParcel(Parcel in) { - return new MediaItem2(in); - } - - @Override - public MediaItem2[] newArray(int size) { - return new MediaItem2[size]; - } - }; - - private static final long UNKNOWN_TIME = -1; - - private final long mStartPositionMs; - private final long mEndPositionMs; - - private final Object mLock = new Object(); - - @GuardedBy("mLock") - private MediaMetadata mMetadata; - @GuardedBy("mLock") - private final List<Pair<OnMetadataChangedListener, Executor>> mListeners = new ArrayList<>(); - - /** - * Used by {@link MediaItem2.Builder}. - */ - // Note: Needs to be protected when we want to allow 3rd party player to define customized - // MediaItem2. - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(Builder builder) { - this(builder.mMetadata, builder.mStartPositionMs, builder.mEndPositionMs); - } - - /** - * Used by Parcelable.Creator. - */ - // Note: Needs to be protected when we want to allow 3rd party player to define customized - // MediaItem2. - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(Parcel in) { - this(in.readParcelable(MediaItem2.class.getClassLoader()), in.readLong(), in.readLong()); - } - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(MediaItem2 item) { - this(item.mMetadata, item.mStartPositionMs, item.mEndPositionMs); - } - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(@Nullable MediaMetadata metadata, long startPositionMs, long endPositionMs) { - if (startPositionMs > endPositionMs) { - throw new IllegalArgumentException("Illegal start/end position: " - + startPositionMs + " : " + endPositionMs); - } - if (metadata != null && metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) { - long durationMs = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION); - if (durationMs != UNKNOWN_TIME && endPositionMs != POSITION_UNKNOWN - && endPositionMs > durationMs) { - throw new IllegalArgumentException("endPositionMs shouldn't be greater than" - + " duration in the metdata, endPositionMs=" + endPositionMs - + ", durationMs=" + durationMs); - } - } - mMetadata = metadata; - mStartPositionMs = startPositionMs; - mEndPositionMs = endPositionMs; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(getClass().getSimpleName()); - synchronized (mLock) { - sb.append("{mMetadata=").append(mMetadata); - sb.append(", mStartPositionMs=").append(mStartPositionMs); - sb.append(", mEndPositionMs=").append(mEndPositionMs); - sb.append('}'); - } - return sb.toString(); - } - - /** - * Sets metadata. If the metadata is not {@code null}, its id should be matched with this - * instance's media id. - * - * @param metadata metadata to update - * @see MediaMetadata#METADATA_KEY_MEDIA_ID - */ - public void setMetadata(@Nullable MediaMetadata metadata) { - List<Pair<OnMetadataChangedListener, Executor>> listeners = new ArrayList<>(); - synchronized (mLock) { - if (mMetadata != null && metadata != null - && !TextUtils.equals(getMediaId(), metadata.getString(METADATA_KEY_MEDIA_ID))) { - Log.d(TAG, "MediaItem2's media ID shouldn't be changed"); - return; - } - mMetadata = metadata; - listeners.addAll(mListeners); - } - - for (Pair<OnMetadataChangedListener, Executor> pair : listeners) { - final OnMetadataChangedListener listener = pair.first; - pair.second.execute(new Runnable() { - @Override - public void run() { - listener.onMetadataChanged(MediaItem2.this); - } - }); - } - } - - /** - * Gets the metadata of the media. - * - * @return metadata from the session - */ - public @Nullable MediaMetadata getMetadata() { - synchronized (mLock) { - return mMetadata; - } - } - - /** - * Return the position in milliseconds at which the playback will start. - * @return the position in milliseconds at which the playback will start - */ - public long getStartPosition() { - return mStartPositionMs; - } - - /** - * Return the position in milliseconds at which the playback will end. - * {@link #POSITION_UNKNOWN} means ending at the end of source content. - * @return the position in milliseconds at which the playback will end - */ - public long getEndPosition() { - return mEndPositionMs; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mMetadata, 0); - dest.writeLong(mStartPositionMs); - dest.writeLong(mEndPositionMs); - } - - /** - * Gets the media id for this item. If it's not {@code null}, it's a persistent unique key - * for the underlying media content. - * - * @return media Id from the session - */ - @Nullable String getMediaId() { - synchronized (mLock) { - return mMetadata != null - ? mMetadata.getString(METADATA_KEY_MEDIA_ID) : null; - } - } - - void addOnMetadataChangedListener(Executor executor, OnMetadataChangedListener listener) { - synchronized (mLock) { - for (Pair<OnMetadataChangedListener, Executor> pair : mListeners) { - if (pair.first == listener) { - return; - } - } - mListeners.add(new Pair<>(listener, executor)); - } - } - - void removeOnMetadataChangedListener(OnMetadataChangedListener listener) { - synchronized (mLock) { - for (int i = mListeners.size() - 1; i >= 0; i--) { - if (mListeners.get(i).first == listener) { - mListeners.remove(i); - return; - } - } - } - } - - /** - * Builder for {@link MediaItem2}. - */ - public static final class Builder { - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaMetadata mMetadata; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - long mStartPositionMs = 0; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - long mEndPositionMs = POSITION_UNKNOWN; - - /** - * Set the metadata of this instance. {@code null} for unset. - * - * @param metadata metadata - * @return this instance for chaining - */ - public @NonNull Builder setMetadata(@Nullable MediaMetadata metadata) { - mMetadata = metadata; - return this; - } - - /** - * Sets the start position in milliseconds at which the playback will start. - * Any negative number is treated as 0. - * - * @param position the start position in milliseconds at which the playback will start - * @return the same Builder instance. - */ - public @NonNull Builder setStartPosition(long position) { - if (position < 0) { - position = 0; - } - mStartPositionMs = position; - return this; - } - - /** - * Sets the end position in milliseconds at which the playback will end. - * Any negative number is treated as maximum length of the media item. - * - * @param position the end position in milliseconds at which the playback will end - * @return the same Builder instance. - */ - public @NonNull Builder setEndPosition(long position) { - if (position < 0) { - position = POSITION_UNKNOWN; - } - mEndPositionMs = position; - return this; - } - - /** - * Build {@link MediaItem2}. - * - * @return a new {@link MediaItem2}. - */ - public @NonNull MediaItem2 build() { - return new MediaItem2(this); - } - } - - interface OnMetadataChangedListener { - void onMetadataChanged(MediaItem2 item); - } -} diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java index 72c18f6148f0..614d737e3758 100644 --- a/media/apex/java/android/media/MediaPlayer2.java +++ b/media/apex/java/android/media/MediaPlayer2.java @@ -273,6 +273,8 @@ import java.util.concurrent.atomic.AtomicLong; * Then check the <code>status</code> parameter. The value {@link #CALL_STATUS_NO_ERROR} indicates a * successful transition. Any other value will be an error. Call {@link #getState()} to * determine the current state. </p> + * + * @hide */ public class MediaPlayer2 implements AutoCloseable, AudioRouting { static { diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java index a900d8745006..6b56ae086a0d 100644 --- a/media/apex/java/android/media/MediaSession2.java +++ b/media/apex/java/android/media/MediaSession2.java @@ -17,6 +17,7 @@ package android.media; import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; +import static android.media.MediaConstants.KEY_CONNECTION_HINTS; import static android.media.MediaConstants.KEY_PACKAGE_NAME; import static android.media.MediaConstants.KEY_PID; import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE; @@ -308,8 +309,11 @@ public class MediaSession2 implements AutoCloseable { String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME); RemoteUserInfo remoteUserInfo = new RemoteUserInfo(callingPkg, callingPid, callingUid); - final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo, - mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller); + final ControllerInfo controllerInfo = new ControllerInfo( + remoteUserInfo, + mSessionManager.isTrustedForMediaControl(remoteUserInfo), + controller, + connectionRequest.getBundle(KEY_CONNECTION_HINTS)); mCallbackExecutor.execute(() -> { boolean connected = false; try { @@ -568,6 +572,7 @@ public class MediaSession2 implements AutoCloseable { private final RemoteUserInfo mRemoteUserInfo; private final boolean mIsTrusted; private final Controller2Link mControllerBinder; + private final Bundle mConnectionHints; private final Object mLock = new Object(); //@GuardedBy("mLock") private int mNextSeqNumber; @@ -583,12 +588,16 @@ public class MediaSession2 implements AutoCloseable { * @param remoteUserInfo remote user info * @param trusted {@code true} if trusted, {@code false} otherwise * @param controllerBinder Controller2Link for the connected controller. + * @param connectionHints a session-specific argument sent from the controller for the + * connection. The contents of this bundle may affect the + * connection result. */ ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted, - @Nullable Controller2Link controllerBinder) { + @Nullable Controller2Link controllerBinder, @Nullable Bundle connectionHints) { mRemoteUserInfo = remoteUserInfo; mIsTrusted = trusted; mControllerBinder = controllerBinder; + mConnectionHints = connectionHints; mPendingCommands = new ArrayMap<>(); mRequestedCommandSeqNumbers = new ArraySet<>(); } @@ -617,6 +626,14 @@ public class MediaSession2 implements AutoCloseable { } /** + * @return connection hints sent from controller, or {@link Bundle#EMPTY} if none. + */ + @NonNull + public Bundle getConnectionHints() { + return mConnectionHints == null ? Bundle.EMPTY : new Bundle(mConnectionHints); + } + + /** * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or * has a enabled notification listener so can be trusted to accept connection and incoming * command request. diff --git a/media/apex/java/android/media/MediaSession2Service.java b/media/apex/java/android/media/MediaSession2Service.java index 5bb746a7f9e3..28ead99357bc 100644 --- a/media/apex/java/android/media/MediaSession2Service.java +++ b/media/apex/java/android/media/MediaSession2Service.java @@ -16,6 +16,10 @@ package android.media; +import static android.media.MediaConstants.KEY_CONNECTION_HINTS; +import static android.media.MediaConstants.KEY_PACKAGE_NAME; +import static android.media.MediaConstants.KEY_PID; + import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; @@ -24,6 +28,9 @@ import android.app.NotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.media.MediaSession2.ControllerInfo; +import android.media.session.MediaSessionManager; +import android.media.session.MediaSessionManager.RemoteUserInfo; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -70,6 +77,8 @@ public abstract class MediaSession2Service extends Service { //@GuardedBy("mLock") private NotificationManager mNotificationManager; //@GuardedBy("mLock") + private MediaSessionManager mMediaSessionManager; + //@GuardedBy("mLock") private Intent mStartSelfIntent; //@GuardedBy("mLock") private Map<String, MediaSession2> mSessions = new ArrayMap<>(); @@ -93,6 +102,8 @@ public abstract class MediaSession2Service extends Service { mStartSelfIntent = new Intent(this, this.getClass()); mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + mMediaSessionManager = + (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE); } } @@ -132,34 +143,22 @@ public abstract class MediaSession2Service extends Service { /** * Called when a {@link MediaController2} is created with the this service's - * {@link Session2Token}. Return the primary session for telling the controller which session to - * connect. - * <p> - * Primary session is the highest priority session that this service manages. Here are some - * recommendations of the primary session. - * <ol> - * <li>When there's no {@link MediaSession2}, create and return a new session. Resume the - * playback that the app has the lastly played with the new session. The behavior is what - * framework expects when the framework sends key events to the service.</li> - * <li>When there's multiple {@link MediaSession2}s, pick the session that has the lastly - * started the playback. This is the same way as the framework prioritize sessions to receive - * media key events.</li> - * </ol> + * {@link Session2Token}. Return the session for telling the controller which session to + * connect. Return {@code null} to reject the connection from this controller. * <p> * Session returned here will be added to this service automatically. You don't need to call * {@link #addSession(MediaSession2)} for that. * <p> - * Session service will accept or reject the connection with the - * {@link MediaSession2.SessionCallback} in the session returned here. - * <p> * This method is always called on the main thread. * - * @return a new session + * @param controllerInfo information of the controller which is trying to connect. + * @return a {@link MediaSession2} instance for the controller to connect to, or {@code null} + * to reject connection * @see MediaSession2.Builder * @see #getSessions() */ - @NonNull - public abstract MediaSession2 onGetPrimarySession(); + @Nullable + public abstract MediaSession2 onGetSession(@NonNull ControllerInfo controllerInfo); /** * Called when notification UI needs update. Override this method to show or cancel your own @@ -251,6 +250,16 @@ public abstract class MediaSession2Service extends Service { } /** + * Returns the {@link MediaSessionManager}. + */ + @NonNull + MediaSessionManager getMediaSessionManager() { + synchronized (mLock) { + return mMediaSessionManager; + } + } + + /** * Called by registered {@link MediaSession2.ForegroundServiceEventCallback} * * @param session session with change @@ -365,8 +374,33 @@ public abstract class MediaSession2Service extends Service { Log.d(TAG, "Handling incoming connection request from the" + " controller, controller=" + caller + ", uid=" + uid); } + + String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME); + // The Binder.getCallingPid() can be 0 for an oneway call from the + // remote process. If it's the case, use PID from the connectionRequest. + RemoteUserInfo remoteUserInfo = new RemoteUserInfo( + callingPkg, + pid == 0 ? connectionRequest.getInt(KEY_PID) : pid, + uid); + final ControllerInfo controllerInfo = new ControllerInfo( + remoteUserInfo, + service.getMediaSessionManager() + .isTrustedForMediaControl(remoteUserInfo), + caller, + connectionRequest.getBundle(KEY_CONNECTION_HINTS)); + final MediaSession2 session; - session = service.onGetPrimarySession(); + session = service.onGetSession(controllerInfo); + + if (session == null) { + if (DEBUG) { + Log.d(TAG, "Rejecting incoming connection request from the" + + " controller, controller=" + caller + ", uid=" + uid); + } + // Note: Trusted controllers also can be rejected according to the + // service implementation. + return; + } service.addSession(session); shouldNotifyDisconnected = false; session.onConnect(caller, pid, uid, seq, connectionRequest); @@ -377,8 +411,7 @@ public abstract class MediaSession2Service extends Service { // Trick to call onDisconnected() in one place. if (shouldNotifyDisconnected) { if (DEBUG) { - Log.d(TAG, "Service has destroyed prematurely." - + " Rejecting connection"); + Log.d(TAG, "Notifying the controller of its disconnection"); } try { caller.notifyDisconnected(0); diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java index 7f73dc123063..7c752e198f3a 100644 --- a/media/apex/java/android/media/Session2Command.java +++ b/media/apex/java/android/media/Session2Command.java @@ -30,7 +30,7 @@ import java.util.Objects; * <p> * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command. * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and - * {@link #getCustomCommand()} shouldn't be {@code null}. + * {@link #getCustomAction()} shouldn't be {@code null}. * <p> * Refer to the * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a> @@ -63,8 +63,8 @@ public final class Session2Command implements Parcelable { private final int mCommandCode; // Nonnull if it's custom command - private final String mCustomCommand; - private final Bundle mExtras; + private final String mCustomAction; + private final Bundle mCustomExtras; /** * Constructor for creating a command predefined in AndroidX media2. @@ -76,8 +76,8 @@ public final class Session2Command implements Parcelable { throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM"); } mCommandCode = commandCode; - mCustomCommand = null; - mExtras = null; + mCustomAction = null; + mCustomExtras = null; } /** @@ -91,8 +91,8 @@ public final class Session2Command implements Parcelable { throw new IllegalArgumentException("action shouldn't be null"); } mCommandCode = COMMAND_CODE_CUSTOM; - mCustomCommand = action; - mExtras = extras; + mCustomAction = action; + mCustomExtras = extras; } /** @@ -101,8 +101,8 @@ public final class Session2Command implements Parcelable { @SuppressWarnings("WeakerAccess") /* synthetic access */ Session2Command(Parcel in) { mCommandCode = in.readInt(); - mCustomCommand = in.readString(); - mExtras = in.readBundle(); + mCustomAction = in.readString(); + mCustomExtras = in.readBundle(); } /** @@ -118,8 +118,8 @@ public final class Session2Command implements Parcelable { * This will return {@code null} for a predefined command. */ @Nullable - public String getCustomCommand() { - return mCustomCommand; + public String getCustomAction() { + return mCustomAction; } /** @@ -127,8 +127,8 @@ public final class Session2Command implements Parcelable { * This will return {@code null} for a predefined command. */ @Nullable - public Bundle getExtras() { - return mExtras; + public Bundle getCustomExtras() { + return mCustomExtras; } @Override @@ -142,8 +142,8 @@ public final class Session2Command implements Parcelable { throw new IllegalArgumentException("parcel shouldn't be null"); } dest.writeInt(mCommandCode); - dest.writeString(mCustomCommand); - dest.writeBundle(mExtras); + dest.writeString(mCustomAction); + dest.writeBundle(mCustomExtras); } @Override @@ -153,12 +153,12 @@ public final class Session2Command implements Parcelable { } Session2Command other = (Session2Command) obj; return mCommandCode == other.mCommandCode - && TextUtils.equals(mCustomCommand, other.mCustomCommand); + && TextUtils.equals(mCustomAction, other.mCustomAction); } @Override public int hashCode() { - return Objects.hash(mCustomCommand, mCommandCode); + return Objects.hash(mCustomAction, mCommandCode); } /** diff --git a/media/apex/java/android/media/UriDataSourceDesc.java b/media/apex/java/android/media/UriDataSourceDesc.java index eaedf1e377e2..adf7a7ddddb9 100644 --- a/media/apex/java/android/media/UriDataSourceDesc.java +++ b/media/apex/java/android/media/UriDataSourceDesc.java @@ -18,7 +18,6 @@ package android.media; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.net.Uri; import java.net.HttpCookie; @@ -36,7 +35,6 @@ import java.util.Map; * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}. * @hide */ -@TestApi public class UriDataSourceDesc extends DataSourceDesc { private Uri mUri; private Map<String, String> mHeader; diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index d8640967a30a..e655460c2ba1 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -535,6 +535,23 @@ public final class AudioAttributes implements Parcelable { } /** + * Return the capture policy. + * @return the capture policy set by {@link Builder#setAllowedCapturePolicy(int)} or + * the default if it was not called. + */ + @CapturePolicy + public int getAllowedCapturePolicy() { + if ((mFlags & FLAG_NO_SYSTEM_CAPTURE) == FLAG_NO_SYSTEM_CAPTURE) { + return ALLOW_CAPTURE_BY_NONE; + } + if ((mFlags & FLAG_NO_MEDIA_PROJECTION) == FLAG_NO_MEDIA_PROJECTION) { + return ALLOW_CAPTURE_BY_SYSTEM; + } + return ALLOW_CAPTURE_BY_ALL; + } + + + /** * Builder class for {@link AudioAttributes} objects. * <p> Here is an example where <code>Builder</code> is used to define the * {@link AudioAttributes} to be used by a new <code>AudioTrack</code> instance: @@ -696,12 +713,19 @@ public final class AudioAttributes implements Parcelable { } /** - * Specifying if audio may or may not be captured by other apps or the system. + * Specifies weather the audio may or may not be captured by other apps or the system. * * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}. * - * Note that an application can also set its global policy, in which case the most - * restrictive policy is always applied. + * There are multiple ways to set this policy: + * - for each tracks independently, with this method + * - application wide at runtime, with {@link AudioManager#setAllowedCapturePolicy(int)} + * - application wide at build time, see {@code allowAudioPlaybackCapture} in the + * application manifest. + * The most restrictive policy is always applied. + * + * See {@link AudioPlaybackCaptureConfiguration} for more details on the restrictions + * which audio signals can be captured. * * @param capturePolicy one of * {@link #ALLOW_CAPTURE_BY_ALL}, diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java index 3aaa7dfc05d0..ee89509951df 100644 --- a/media/java/android/media/AudioFocusInfo.java +++ b/media/java/android/media/AudioFocusInfo.java @@ -18,6 +18,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -27,6 +28,7 @@ import java.util.Objects; * @hide * A class to encapsulate information about an audio focus owner or request. */ +@TestApi @SystemApi public final class AudioFocusInfo implements Parcelable { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index d5eee6308ae0..d3471378b9d9 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -26,6 +26,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager; import android.app.PendingIntent; @@ -1483,12 +1484,21 @@ public class AudioManager { } /** - * Specifying if this audio may or may not be captured by other apps or the system. + * Specifies wheather the audio played by this app may or may not be captured by other apps or + * the system. * * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}. * - * Note that each audio track can also set its policy, in which case the most - * restrictive policy is always applied. + * There are multiple ways to set this policy: + * - for each tracks independently, see + * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} + * - application wide at runtime, with this method + * - application wide at build time, see {@code allowAudioPlaybackCapture} in the application + * manifest. + * The most restrictive policy is always applied. + * + * See {@link AudioPlaybackCaptureConfiguration} for more details on the restrictions + * which audio signals can be captured. * * @param capturePolicy one of * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, @@ -1503,7 +1513,22 @@ public class AudioManager { int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags); if (result != AudioSystem.AUDIO_STATUS_OK) { Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); + return; } + mCapturePolicy = capturePolicy; + } + + @AudioAttributes.CapturePolicy + private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL; + + /** + * Return the capture policy. + * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or + * the default if it was not called. + */ + @AudioAttributes.CapturePolicy + public int getAllowedCapturePolicy() { + return mCapturePolicy; } //==================================================================== @@ -3026,6 +3051,7 @@ public class AudioManager { * @param requestResult the result to the focus request to be passed to the requester * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull AudioFocusInfo afi, @@ -3065,6 +3091,7 @@ public class AudioManager { * if there was an error sending the request. * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, @@ -3327,6 +3354,7 @@ public class AudioManager { * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission, * {@link #SUCCESS} otherwise. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull AudioPolicy policy) { @@ -3361,6 +3389,7 @@ public class AudioManager { * Unregisters an {@link AudioPolicy} asynchronously. * @param policy the non-null {@link AudioPolicy} to unregister. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) { @@ -3387,6 +3416,7 @@ public class AudioManager { * associated with mixes of this policy. * @param policy the non-null {@link AudioPolicy} to unregister. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { @@ -3401,6 +3431,20 @@ public class AudioManager { } } + /** + * @hide + * @return true if an AudioPolicy was previously registered + */ + @TestApi + public boolean hasRegisteredDynamicPolicy() { + final IAudioService service = getService(); + try { + return service.hasRegisteredDynamicPolicy(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + //==================================================================== // Notification of playback activity & playback configuration /** diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java index bcaef032093d..fe5005a7cc9a 100644 --- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java +++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java @@ -20,26 +20,35 @@ import android.annotation.NonNull; import android.media.AudioAttributes.AttributeUsage; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioMixingRule; +import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion; import android.media.projection.MediaProjection; import android.os.RemoteException; import com.android.internal.util.Preconditions; +import java.util.function.ToIntFunction; + /** * Configuration for capturing audio played by other apps. * - * Only the following audio can be captured: - * - usage MUST be {@link AudioAttributes#USAGE_UNKNOWN} or {@link AudioAttributes#USAGE_GAME} + * When capturing audio signals played by other apps (and yours), + * you will only capture a mix of the audio signals played by players + * (such as AudioTrack or MediaPlayer) which present the following characteristics: + * - the usage value MUST be {@link AudioAttributes#USAGE_UNKNOWN} or + * {@link AudioAttributes#USAGE_GAME} * or {@link AudioAttributes#USAGE_MEDIA}. All other usages CAN NOT be captured. - * - audio attributes MUST have its ${@link AudioAttributes.Builder#setAllowedCapturePolicy} - * to {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}. - * - played by apps that MUST be in the same user profile as the capturing app - * (eg work profile can not capture user profile apps and vice-versa). - * - played by apps for which the attribute allowAudioPlaybackCapture in their manifest + * - AND the capture policy set by their app (with ${@link AudioManager#setAllowedCapturePolicy}) + * or on each player (with ${@link AudioAttributes.Builder#setAllowedCapturePolicy}) is + * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, whichever is the most strict. + * - AND their app attribute allowAudioPlaybackCapture in their manifest * MUST either be: * * set to "true" - * * not set, and their targetSdkVersion MUST be equal or higher to + * * not set, and their {@code targetSdkVersion} MUST be equal or higher to * {@link android.os.Build.VERSION_CODES#Q}. + * Ie. Apps that do not target at least Android Q must explicitly opt-in to be captured by a + * MediaProjection. + * - AND their apps MUST be in the same user profile as your app + * (eg work profile can not capture user profile apps and vice-versa). * * <p>An example for creating a capture configuration for capturing all media playback: * @@ -77,6 +86,39 @@ public final class AudioPlaybackCaptureConfiguration { return mProjection; } + /** @return the usages passed to {@link Builder#addMatchingUsage(int)}. */ + @AttributeUsage + public @NonNull int[] getMatchingUsages() { + return getIntPredicates(AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE, + criterion -> criterion.getAudioAttributes().getUsage()); + } + + /** @return the UIDs passed to {@link Builder#addMatchingUid(int)}. */ + public @NonNull int[] getMatchingUids() { + return getIntPredicates(AudioMixingRule.RULE_MATCH_UID, + criterion -> criterion.getIntProp()); + } + + /** @return the usages passed to {@link Builder#excludeUsage(int)}. */ + @AttributeUsage + public @NonNull int[] getExcludeUsages() { + return getIntPredicates(AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE, + criterion -> criterion.getAudioAttributes().getUsage()); + } + + /** @return the UIDs passed to {@link Builder#excludeUid(int)}. */ + public @NonNull int[] getExcludeUids() { + return getIntPredicates(AudioMixingRule.RULE_EXCLUDE_UID, + criterion -> criterion.getIntProp()); + } + + private int[] getIntPredicates(int rule, + ToIntFunction<AudioMixMatchCriterion> getPredicate) { + return mAudioMixingRule.getCriteria().stream() + .filter(criterion -> criterion.getRule() == rule) + .mapToInt(getPredicate) + .toArray(); + } /** * Returns a mix that routes audio back into the app while still playing it from the speakers. diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 790e189e9109..d9d614f7ead4 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -975,13 +975,9 @@ public class AudioTrack extends PlayerBase throw new UnsupportedOperationException( "Offload and low latency modes are incompatible"); } - if (mAttributes.getUsage() != AudioAttributes.USAGE_MEDIA) { - throw new UnsupportedOperationException( - "Cannot create AudioTrack, offload requires USAGE_MEDIA"); - } if (!AudioSystem.isOffloadSupported(mFormat, mAttributes)) { throw new UnsupportedOperationException( - "Cannot create AudioTrack, offload format not supported"); + "Cannot create AudioTrack, offload format / attributes not supported"); } } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index eddbee46252e..85de00a2a989 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -211,6 +211,8 @@ interface IAudioService { void setVolumePolicy(in VolumePolicy policy); + boolean hasRegisteredDynamicPolicy(); + void registerRecordingCallback(in IRecordingConfigDispatcher rcdb); oneway void unregisterRecordingCallback(in IRecordingConfigDispatcher rcdb); diff --git a/media/java/android/media/IMediaRoute2Callback.aidl b/media/java/android/media/IMediaRoute2Callback.aidl deleted file mode 100644 index f03c8ab444c4..000000000000 --- a/media/java/android/media/IMediaRoute2Callback.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -/** - * @hide - */ -oneway interface IMediaRoute2Callback { - void onRouteSelected(int uid, String routeId); -} diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl deleted file mode 100644 index b97dcc521a04..000000000000 --- a/media/java/android/media/IMediaRoute2Provider.aidl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -import android.media.IMediaRoute2Callback; - -/** - * {@hide} - */ -oneway interface IMediaRoute2Provider { - void setCallback(IMediaRoute2Callback callback); - void selectRoute(int uid, String id); -} diff --git a/media/java/android/media/IMediaRouter2ManagerClient.aidl b/media/java/android/media/IMediaRouter2ManagerClient.aidl deleted file mode 100644 index 234551b37a10..000000000000 --- a/media/java/android/media/IMediaRouter2ManagerClient.aidl +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -/** - * {@hide} - */ -oneway interface IMediaRouter2ManagerClient { - void onRouteSelected(int uid, String routeId); - void onControlCategoriesChanged(int uid, in List<String> categories); -} diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 59f1d0dcbed8..3308fc929b03 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -17,7 +17,6 @@ package android.media; import android.media.IMediaRouterClient; -import android.media.IMediaRouter2ManagerClient; import android.media.MediaRouterClientState; /** @@ -30,15 +29,8 @@ interface IMediaRouterService { MediaRouterClientState getState(IMediaRouterClient client); boolean isPlaybackActive(IMediaRouterClient client); - void setControlCategories(IMediaRouterClient client, in List<String> categories); void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan); void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); void requestSetVolume(IMediaRouterClient client, String routeId, int volume); void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction); - - void registerManagerAsUser(IMediaRouter2ManagerClient callback, - String packageName, int userId); - void unregisterManager(IMediaRouter2ManagerClient callback); - void setRemoteRoute(IMediaRouter2ManagerClient callback, - int uid, String routeId, boolean explicit); } diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java deleted file mode 100644 index 04ddc3089b91..000000000000 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; - -import android.app.Service; -import android.content.Intent; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.RemoteException; -import android.util.Log; - -/** - * @hide - */ -public abstract class MediaRoute2ProviderService extends Service { - private static final String TAG = "MediaRouteProviderSrv"; - - public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService"; - - private final Handler mHandler; - private ProviderStub mStub; - private IMediaRoute2Callback mCallback; - - public MediaRoute2ProviderService() { - mHandler = new Handler(Looper.getMainLooper()); - } - - @Override - public IBinder onBind(Intent intent) { - if (SERVICE_INTERFACE.equals(intent.getAction())) { - if (mStub == null) { - mStub = new ProviderStub(); - } - return mStub; - } - return null; - } - - /** - * Called when selectRoute is called on a route of the provider. - * - * @param uid The target application uid - * @param routeId The id of the target route - */ - public abstract void onSelect(int uid, String routeId); - - /** - * Updates provider info from selected route and appliation. - * - * TODO: When provider descriptor is defined, this should update the descriptor correctly. - * - * @param uid - * @param routeId - */ - public void updateProvider(int uid, String routeId) { - if (mCallback != null) { - try { - //TODO: After publishState() is fully implemented, delete this. - mCallback.onRouteSelected(uid, routeId); - } catch (RemoteException ex) { - Log.d(TAG, "Failed to update provider"); - } - } - publishState(); - } - - void setCallback(IMediaRoute2Callback callback) { - mCallback = callback; - publishState(); - } - - void publishState() { - //TODO: Send provider descriptor to the MediaRouterService - } - - final class ProviderStub extends IMediaRoute2Provider.Stub { - ProviderStub() { } - - @Override - public void setCallback(IMediaRoute2Callback callback) { - mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::setCallback, - MediaRoute2ProviderService.this, callback)); - } - - @Override - public void selectRoute(int uid, String id) { - mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelect, - MediaRoute2ProviderService.this, uid, id)); - } - } -} diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 5a89d8c82f3a..3444e9277949 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -347,17 +347,6 @@ public class MediaRouter { return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); } - void setControlCategories(List<String> categories) { - if (mClient != null) { - try { - mMediaRouterService.setControlCategories(mClient, - categories); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to set control categories.", ex); - } - } - } - private void updatePresentationDisplays(int changedDisplayId) { final int count = mRoutes.size(); for (int i = 0; i < count; i++) { @@ -930,25 +919,6 @@ public class MediaRouter { return -1; } - //TODO: Remove @hide when it is ready. - //TODO: Provide pre-defined categories for app developers. - /** - * Sets control categories of the client application. - * Control categories can be used to filter out media routes - * that don't correspond with the client application. - * The only routes that match any of the categories will be shown on other applications. - * - * @hide - * @param categories Categories to set - */ - public void setControlCategories(@NonNull List<String> categories) { - if (categories == null) { - throw new IllegalArgumentException("Categories must not be null"); - } - sStatic.setControlCategories(categories); - } - - /** * Select the specified route to use for output of the given media types. * <p class="note"> diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java deleted file mode 100644 index ac5958ea9aa1..000000000000 --- a/media/java/android/media/MediaRouter2Manager.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; - -import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.content.Context; -import android.os.Handler; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; -import android.util.Log; - -import com.android.internal.annotations.GuardedBy; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; - -/** - * @hide - */ -public class MediaRouter2Manager { - private static final String TAG = "MediaRouter2Manager"; - private static final Object sLock = new Object(); - - @GuardedBy("sLock") - private static MediaRouter2Manager sInstance; - - final String mPackageName; - - private Context mContext; - private Client mClient; - private final IMediaRouterService mMediaRouterService; - final Handler mHandler; - - @GuardedBy("sLock") - final ArrayList<CallbackRecord> mCallbacks = new ArrayList<>(); - - /** - * Gets an instance of media router manager that controls media route of other apps. - * @param context - * @return - */ - public static MediaRouter2Manager getInstance(@NonNull Context context) { - if (context == null) { - throw new IllegalArgumentException("context must not be null"); - } - synchronized (sLock) { - if (sInstance == null) { - sInstance = new MediaRouter2Manager(context); - } - return sInstance; - } - } - - private MediaRouter2Manager(Context context) { - mContext = context.getApplicationContext(); - mMediaRouterService = IMediaRouterService.Stub.asInterface( - ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); - mPackageName = mContext.getPackageName(); - mHandler = new Handler(context.getMainLooper()); - } - - /** - * Registers a callback to listen route info. - * - * @param executor The executor that runs the callback. - * @param callback The callback to add. - */ - public void addCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull Callback callback) { - - if (executor == null) { - throw new IllegalArgumentException("executor must not be null"); - } - if (callback == null) { - throw new IllegalArgumentException("callback must not be null"); - } - - synchronized (sLock) { - final int index = findCallbackRecord(callback); - if (index >= 0) { - Log.w(TAG, "Ignore adding the same callback twice."); - return; - } - if (mCallbacks.size() == 0) { - Client client = new Client(); - try { - mMediaRouterService.registerManagerAsUser(client, mPackageName, - UserHandle.myUserId()); - mClient = client; - } catch (RemoteException ex) { - Log.e(TAG, "Unable to register media router manager.", ex); - } - } - mCallbacks.add(new CallbackRecord(executor, callback)); - } - } - - /** - * Removes the specified callback. - * - * @param callback The callback to remove. - */ - public void removeCallback(@NonNull Callback callback) { - if (callback == null) { - throw new IllegalArgumentException("callback must not be null"); - } - - synchronized (sLock) { - final int index = findCallbackRecord(callback); - if (index < 0) { - Log.w(TAG, "Ignore removing unknown callback. " + callback); - return; - } - mCallbacks.remove(index); - if (mCallbacks.size() == 0 && mClient != null) { - try { - mMediaRouterService.unregisterManager(mClient); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to unregister media router manager", ex); - } - mClient = null; - } - } - } - - private int findCallbackRecord(Callback callback) { - final int count = mCallbacks.size(); - for (int i = 0; i < count; i++) { - if (mCallbacks.get(i).mCallback == callback) { - return i; - } - } - return -1; - } - - /** - * Selects media route for the specified application uid. - * - * @param uid The uid of the application that should change it's media route. - * @param routeId The id of the route to select - */ - public void selectRoute(int uid, String routeId) { - if (mClient != null) { - try { - mMediaRouterService.setRemoteRoute(mClient, uid, routeId, /* explicit= */true); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to select media route", ex); - } - } - } - - /** - * Unselects media route for the specified application uid. - * - * @param uid The uid of the application that should stop routing. - */ - public void unselectRoute(int uid) { - if (mClient != null) { - try { - mMediaRouterService.setRemoteRoute(mClient, uid, null, /* explicit= */ true); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to select media route", ex); - } - } - } - - void notifyRouteSelected(int uid, String routeId) { - for (CallbackRecord record : mCallbacks) { - record.mExecutor.execute(() -> record.mCallback.onRouteSelected(uid, routeId)); - } - } - - void notifyControlCategoriesChanged(int uid, List<String> categories) { - for (CallbackRecord record : mCallbacks) { - record.mExecutor.execute( - () -> record.mCallback.onControlCategoriesChanged(uid, categories)); - } - } - - /** - * Interface for receiving events about media routing changes. - */ - public abstract static class Callback { - /** - * Called when a route is selected for some application uid. - * @param uid - * @param routeId - */ - public abstract void onRouteSelected(int uid, String routeId); - - /** - * Called when the control categories of an application is changed. - * @param uid the uid of the app that changed control categories - * @param categories the changed categories - */ - public abstract void onControlCategoriesChanged(int uid, List<String> categories); - } - - final class CallbackRecord { - public final Executor mExecutor; - public final Callback mCallback; - - CallbackRecord(Executor executor, Callback callback) { - mExecutor = executor; - mCallback = callback; - } - } - - class Client extends IMediaRouter2ManagerClient.Stub { - @Override - public void onRouteSelected(int uid, String routeId) { - mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyRouteSelected, - MediaRouter2Manager.this, uid, routeId)); - } - - @Override - public void onControlCategoriesChanged(int uid, List<String> categories) { - mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyControlCategoriesChanged, - MediaRouter2Manager.this, uid, categories)); - } - } -} diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java deleted file mode 100644 index f704acde7cf7..000000000000 --- a/media/java/android/media/MiniThumbFile.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 2009 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.annotation.UnsupportedAppUsage; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.util.Log; - -import dalvik.system.VMRuntime; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.util.Hashtable; - -/** - * This class handles the mini-thumb file. A mini-thumb file consists - * of blocks, indexed by id. Each block has BYTES_PER_MINTHUMB bytes in the - * following format: - * - * 1 byte status (0 = empty, 1 = mini-thumb available) - * 8 bytes magic (a magic number to match what's in the database) - * 4 bytes data length (LEN) - * LEN bytes jpeg data - * (the remaining bytes are unused) - * - * @hide This file is shared between MediaStore and MediaProvider and should remained internal use - * only. - * @deprecated thumbnails are now maintained in separate files, and this file - * format is no longer used. - */ -@Deprecated -public class MiniThumbFile { - private static final String TAG = "MiniThumbFile"; - private static final int MINI_THUMB_DATA_FILE_VERSION = 4; - public static final int BYTES_PER_MINTHUMB = 10000; - private static final int HEADER_SIZE = 1 + 8 + 4; - private Uri mUri; - private RandomAccessFile mMiniThumbFile; - private FileChannel mChannel; - private ByteBuffer mBuffer; - private ByteBuffer mEmptyBuffer; - private static final Hashtable<String, MiniThumbFile> sThumbFiles = - new Hashtable<String, MiniThumbFile>(); - - /** - * We store different types of thumbnails in different files. To remain backward compatibility, - * we should hashcode of content://media/external/images/media remains the same. - */ - @UnsupportedAppUsage - public static synchronized void reset() { - for (MiniThumbFile file : sThumbFiles.values()) { - file.deactivate(); - } - sThumbFiles.clear(); - } - - public static synchronized MiniThumbFile instance(Uri uri) { - if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) { - throw new UnsupportedOperationException(); - } - String type = uri.getPathSegments().get(1); - MiniThumbFile file = sThumbFiles.get(type); - // Log.v(TAG, "get minithumbfile for type: "+type); - if (file == null) { - file = new MiniThumbFile( - Uri.parse("content://media/external/" + type + "/media")); - sThumbFiles.put(type, file); - } - - return file; - } - - private String randomAccessFilePath(int version) { - String directoryName = - Environment.getExternalStorageDirectory().toString() - + "/DCIM/.thumbnails"; - return directoryName + "/.thumbdata" + version + "-" + mUri.hashCode(); - } - - private void removeOldFile() { - String oldPath = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION - 1); - File oldFile = new File(oldPath); - if (oldFile.exists()) { - try { - oldFile.delete(); - } catch (SecurityException ex) { - // ignore - } - } - } - - private RandomAccessFile miniThumbDataFile() { - if (mMiniThumbFile == null) { - removeOldFile(); - String path = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION); - File directory = new File(path).getParentFile(); - if (!directory.isDirectory()) { - if (!directory.mkdirs()) { - Log.e(TAG, "Unable to create .thumbnails directory " - + directory.toString()); - } - } - File f = new File(path); - try { - mMiniThumbFile = new RandomAccessFile(f, "rw"); - } catch (IOException ex) { - // Open as read-only so we can at least read the existing - // thumbnails. - try { - mMiniThumbFile = new RandomAccessFile(f, "r"); - } catch (IOException ex2) { - // ignore exception - } - } - if (mMiniThumbFile != null) { - mChannel = mMiniThumbFile.getChannel(); - } - } - return mMiniThumbFile; - } - - private MiniThumbFile(Uri uri) { - mUri = uri; - mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); - mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); - } - - public synchronized void deactivate() { - if (mMiniThumbFile != null) { - try { - mMiniThumbFile.close(); - mMiniThumbFile = null; - } catch (IOException ex) { - // ignore exception - } - } - } - - // Get the magic number for the specified id in the mini-thumb file. - // Returns 0 if the magic is not available. - public synchronized long getMagic(long id) { - // check the mini thumb file for the right data. Right is - // defined as having the right magic number at the offset - // reserved for this "id". - RandomAccessFile r = miniThumbDataFile(); - if (r != null) { - long pos = id * BYTES_PER_MINTHUMB; - FileLock lock = null; - try { - mBuffer.clear(); - mBuffer.limit(1 + 8); - - lock = mChannel.lock(pos, 1 + 8, true); - // check that we can read the following 9 bytes - // (1 for the "status" and 8 for the long) - if (mChannel.read(mBuffer, pos) == 9) { - mBuffer.position(0); - if (mBuffer.get() == 1) { - return mBuffer.getLong(); - } - } - } catch (IOException ex) { - Log.v(TAG, "Got exception checking file magic: ", ex); - } catch (RuntimeException ex) { - // Other NIO related exception like disk full, read only channel..etc - Log.e(TAG, "Got exception when reading magic, id = " + id + - ", disk full or mount read-only? " + ex.getClass()); - } finally { - try { - if (lock != null) lock.release(); - } - catch (IOException ex) { - // ignore it. - } - } - } - return 0; - } - - public synchronized void eraseMiniThumb(long id) { - RandomAccessFile r = miniThumbDataFile(); - if (r != null) { - long pos = id * BYTES_PER_MINTHUMB; - FileLock lock = null; - try { - mBuffer.clear(); - mBuffer.limit(1 + 8); - - lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false); - // check that we can read the following 9 bytes - // (1 for the "status" and 8 for the long) - if (mChannel.read(mBuffer, pos) == 9) { - mBuffer.position(0); - if (mBuffer.get() == 1) { - long currentMagic = mBuffer.getLong(); - if (currentMagic == 0) { - // there is no thumbnail stored here - Log.i(TAG, "no thumbnail for id " + id); - return; - } - // zero out the thumbnail slot - // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic - // + " at offset " + pos); - mChannel.write(mEmptyBuffer, pos); - } - } else { - // Log.v(TAG, "No slot"); - } - } catch (IOException ex) { - Log.v(TAG, "Got exception checking file magic: ", ex); - } catch (RuntimeException ex) { - // Other NIO related exception like disk full, read only channel..etc - Log.e(TAG, "Got exception when reading magic, id = " + id + - ", disk full or mount read-only? " + ex.getClass()); - } finally { - try { - if (lock != null) lock.release(); - } - catch (IOException ex) { - // ignore it. - } - } - } else { - // Log.v(TAG, "No data file"); - } - } - - public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic) - throws IOException { - RandomAccessFile r = miniThumbDataFile(); - if (r == null) return; - - long pos = id * BYTES_PER_MINTHUMB; - FileLock lock = null; - try { - if (data != null) { - if (data.length > BYTES_PER_MINTHUMB - HEADER_SIZE) { - // not enough space to store it. - return; - } - mBuffer.clear(); - mBuffer.put((byte) 1); - mBuffer.putLong(magic); - mBuffer.putInt(data.length); - mBuffer.put(data); - mBuffer.flip(); - - lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false); - mChannel.write(mBuffer, pos); - } - } catch (IOException ex) { - Log.e(TAG, "couldn't save mini thumbnail data for " - + id + "; ", ex); - throw ex; - } catch (RuntimeException ex) { - // Other NIO related exception like disk full, read only channel..etc - Log.e(TAG, "couldn't save mini thumbnail data for " - + id + "; disk full or mount read-only? " + ex.getClass()); - } finally { - try { - if (lock != null) lock.release(); - } - catch (IOException ex) { - // ignore it. - } - } - } - - /** - * Gallery app can use this method to retrieve mini-thumbnail. Full size - * images share the same IDs with their corresponding thumbnails. - * - * @param id the ID of the image (same of full size image). - * @param data the buffer to store mini-thumbnail. - */ - public synchronized byte [] getMiniThumbFromFile(long id, byte [] data) { - RandomAccessFile r = miniThumbDataFile(); - if (r == null) return null; - - long pos = id * BYTES_PER_MINTHUMB; - FileLock lock = null; - try { - mBuffer.clear(); - lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, true); - int size = mChannel.read(mBuffer, pos); - if (size > 1 + 8 + 4) { // flag, magic, length - mBuffer.position(0); - byte flag = mBuffer.get(); - long magic = mBuffer.getLong(); - int length = mBuffer.getInt(); - - if (size >= 1 + 8 + 4 + length && length != 0 && magic != 0 && flag == 1 && - data.length >= length) { - mBuffer.get(data, 0, length); - return data; - } - } - } catch (IOException ex) { - Log.w(TAG, "got exception when reading thumbnail id=" + id + ", exception: " + ex); - } catch (RuntimeException ex) { - // Other NIO related exception like disk full, read only channel..etc - Log.e(TAG, "Got exception when reading thumbnail, id = " + id + - ", disk full or mount read-only? " + ex.getClass()); - } finally { - try { - if (lock != null) lock.release(); - } - catch (IOException ex) { - // ignore it. - } - } - return null; - } -} diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index 09f17c099609..2f03d26830f2 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -19,6 +19,7 @@ package android.media.audiopolicy; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.media.AudioDeviceInfo; import android.media.AudioFormat; @@ -31,6 +32,7 @@ import java.util.Objects; /** * @hide */ +@TestApi @SystemApi public class AudioMix { diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java index 947b06cdf6b2..ed2fdae71fb0 100644 --- a/media/java/android/media/audiopolicy/AudioMixingRule.java +++ b/media/java/android/media/audiopolicy/AudioMixingRule.java @@ -18,6 +18,7 @@ package android.media.audiopolicy; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.media.AudioAttributes; import android.os.Parcel; @@ -41,6 +42,7 @@ import java.util.Objects; * .build(); * </pre> */ +@TestApi @SystemApi public class AudioMixingRule { @@ -92,7 +94,8 @@ public class AudioMixingRule { public static final int RULE_EXCLUDE_UID = RULE_EXCLUSION_MASK | RULE_MATCH_UID; - static final class AudioMixMatchCriterion { + /** @hide */ + public static final class AudioMixMatchCriterion { @UnsupportedAppUsage final AudioAttributes mAttr; @UnsupportedAppUsage @@ -137,6 +140,10 @@ public class AudioMixingRule { dest.writeInt(-1); } } + + public AudioAttributes getAudioAttributes() { return mAttr; } + public int getIntProp() { return mIntProp; } + public int getRule() { return mRule; } } boolean isAffectingUsage(int usage) { @@ -163,7 +170,8 @@ public class AudioMixingRule { int getTargetMixType() { return mTargetMixType; } @UnsupportedAppUsage private final ArrayList<AudioMixMatchCriterion> mCriteria; - ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; } + /** @hide */ + public ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; } @UnsupportedAppUsage private boolean mAllowPrivilegedPlaybackCapture = false; diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 00f601388164..1cd60f78886e 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; @@ -55,6 +56,7 @@ import java.util.List; * @hide * AudioPolicy provides access to the management of audio routing and audio focus. */ +@TestApi @SystemApi public class AudioPolicy { @@ -237,6 +239,7 @@ public class AudioPolicy { } /** + * @hide * Test method to declare whether this audio focus policy is for test purposes only. * Having a test policy registered will disable the current focus policy and replace it * with this test policy. When unregistered, the previous focus policy will be restored. @@ -245,6 +248,7 @@ public class AudioPolicy { * @param isTestFocusPolicy true if the focus policy to register is for testing purposes. * @return the same Builder instance */ + @TestApi @NonNull public Builder setIsTestFocusPolicy(boolean isTestFocusPolicy) { mIsTestFocusPolicy = isTestFocusPolicy; diff --git a/media/tests/MediaRouteProvider/Android.bp b/media/tests/MediaRouteProvider/Android.bp deleted file mode 100644 index da4282495ac2..000000000000 --- a/media/tests/MediaRouteProvider/Android.bp +++ /dev/null @@ -1,18 +0,0 @@ -android_test { - name: "mediarouteprovider", - - srcs: ["**/*.java"], - - libs: [ - "android.test.runner", - "android.test.base", - ], - - static_libs: [ - "android-support-test", - "mockito-target-minus-junit4", - ], - - platform_apis: true, - certificate: "platform", -}
\ No newline at end of file diff --git a/media/tests/MediaRouteProvider/AndroidManifest.xml b/media/tests/MediaRouteProvider/AndroidManifest.xml deleted file mode 100644 index 489a6214ecbd..000000000000 --- a/media/tests/MediaRouteProvider/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.mediarouteprovider.example"> - - <application android:label="@string/app_name"> - <uses-library android:name="android.test.runner" /> - <service android:name=".SampleMediaRoute2ProviderService" - android:label="@string/app_name" - android:exported="true"> - <intent-filter> - <action android:name="android.media.MediaRoute2ProviderService" /> - </intent-filter> - </service> - </application> -</manifest> diff --git a/media/tests/MediaRouteProvider/res/values/strings.xml b/media/tests/MediaRouteProvider/res/values/strings.xml deleted file mode 100644 index bb970641ffda..000000000000 --- a/media/tests/MediaRouteProvider/res/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <!-- name of the app [CHAR LIMIT=25]--> - <string name="app_name">SampleMediaRouteProvider</string> -</resources>
\ No newline at end of file diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java deleted file mode 100644 index 22fbd85d6979..000000000000 --- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.mediarouteprovider.example; - -import android.content.Intent; -import android.media.MediaRoute2ProviderService; -import android.os.IBinder; - -public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService { - @Override - public IBinder onBind(Intent intent) { - return super.onBind(intent); - } - - @Override - public void onSelect(int uid, String routeId) { - updateProvider(uid, routeId); - } -} diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp deleted file mode 100644 index 611b25a2f128..000000000000 --- a/media/tests/MediaRouter/Android.bp +++ /dev/null @@ -1,18 +0,0 @@ -android_test { - name: "mediaroutertest", - - srcs: ["**/*.java"], - - libs: [ - "android.test.runner", - "android.test.base", - ], - - static_libs: [ - "android-support-test", - "mockito-target-minus-junit4", - ], - - platform_apis: true, - certificate: "platform", -}
\ No newline at end of file diff --git a/media/tests/MediaRouter/AndroidManifest.xml b/media/tests/MediaRouter/AndroidManifest.xml deleted file mode 100644 index a34a264e1247..000000000000 --- a/media/tests/MediaRouter/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.mediaroutertest"> - - <uses-permission android:name="android.permission.CONTROL_MEDIA_ROUTE" /> - - <application android:label="@string/app_name"> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.mediaroutertest" - android:label="MediaRouter Tests"/> -</manifest> diff --git a/media/tests/MediaRouter/AndroidTest.xml b/media/tests/MediaRouter/AndroidTest.xml deleted file mode 100644 index 1301062db496..000000000000 --- a/media/tests/MediaRouter/AndroidTest.xml +++ /dev/null @@ -1,16 +0,0 @@ -<configuration description="Runs sample instrumentation test."> - <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> - <option name="test-file-name" value="mediaroutertest.apk"/> - </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/> - <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/> - <option name="test-suite-tag" value="apct"/> - <option name="test-tag" value="MediaRouterTest"/> - - <test class="com.android.tradefed.testtype.AndroidJUnitTest"> - <option name="package" value="com.android.mediaroutertest"/> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> - <option name="hidden-api-checks" value="false"/> - </test> -</configuration> diff --git a/media/tests/MediaRouter/res/values/strings.xml b/media/tests/MediaRouter/res/values/strings.xml deleted file mode 100644 index 07370207a3c9..000000000000 --- a/media/tests/MediaRouter/res/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <!-- name of the app [CHAR LIMIT=25]--> - <string name="app_name">mediaRouterTest</string> -</resources>
\ No newline at end of file diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java deleted file mode 100644 index a4bde6592516..000000000000 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.mediaroutertest; - -import static org.mockito.Mockito.after; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.media.MediaRouter; -import android.media.MediaRouter2Manager; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class MediaRouterManagerTest { - private static final String TAG = "MediaRouterManagerTest"; - - private static final int TARGET_UID = 109992; - private static final String ROUTE_1 = "MediaRoute1"; - - private static final int AWAIT_MS = 1000; - private static final int TIMEOUT_MS = 1000; - - private Context mContext; - private MediaRouter2Manager mManager; - private MediaRouter mRouter; - private Executor mExecutor; - - private static final List<String> TEST_CONTROL_CATEGORIES = new ArrayList(); - private static final String CONTROL_CATEGORY_1 = "android.media.mediarouter.MEDIA1"; - private static final String CONTROL_CATEGORY_2 = "android.media.mediarouter.MEDIA2"; - static { - TEST_CONTROL_CATEGORIES.add(CONTROL_CATEGORY_1); - TEST_CONTROL_CATEGORIES.add(CONTROL_CATEGORY_2); - } - - @Before - public void setUp() throws Exception { - mContext = InstrumentationRegistry.getTargetContext(); - mManager = MediaRouter2Manager.getInstance(mContext); - mRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); - mExecutor = new ThreadPoolExecutor( - 1, 20, 3, TimeUnit.SECONDS, - new SynchronousQueue<Runnable>()); - } - - @Test - public void transferTest() throws Exception { - MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); - - mManager.addCallback(mExecutor, mockCallback); - - verify(mockCallback, after(AWAIT_MS).never()) - .onRouteSelected(eq(TARGET_UID), any(String.class)); - - mManager.selectRoute(TARGET_UID, ROUTE_1); - verify(mockCallback, timeout(TIMEOUT_MS)).onRouteSelected(TARGET_UID, ROUTE_1); - - mManager.removeCallback(mockCallback); - } - - @Test - public void controlCategoryTest() throws Exception { - final int uid = android.os.Process.myUid(); - - MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); - mManager.addCallback(mExecutor, mockCallback); - - verify(mockCallback, after(AWAIT_MS).never()).onControlCategoriesChanged(eq(uid), - any(List.class)); - - mRouter.setControlCategories(TEST_CONTROL_CATEGORIES); - verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce()) - .onControlCategoriesChanged(uid, TEST_CONTROL_CATEGORIES); - - mManager.removeCallback(mockCallback); - } - -} diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 44e8874f8386..efebfc2a4a1e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.car; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.car.drivingstate.CarDrivingStateEvent; @@ -39,6 +40,7 @@ import com.android.car.notification.CarUxRestrictionManagerWrapper; import com.android.car.notification.NotificationClickHandlerFactory; import com.android.car.notification.NotificationViewController; import com.android.car.notification.PreprocessingManager; +import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.BatteryMeterView; import com.android.systemui.CarSystemUIFactory; @@ -259,8 +261,8 @@ public class CarStatusBar extends StatusBar implements @Override - protected void makeStatusBarView() { - super.makeStatusBarView(); + protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) { + super.makeStatusBarView(result); mHvacController = new HvacController(mContext); CarSystemUIFactory factory = SystemUIFactory.getInstance(); @@ -432,7 +434,7 @@ public class CarStatusBar extends StatusBar implements } @Override - protected void createNavigationBar() { + protected void createNavigationBar(@Nullable RegisterStatusBarResult result) { mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar); mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar); mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar); @@ -443,7 +445,7 @@ public class CarStatusBar extends StatusBar implements // There has been a car customized nav bar on the default display, so just create nav bars // on external displays. - mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */); + mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */, result); } private void buildNavBarContent() { diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java index 55c9361ce6c4..81c5bcd47981 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java @@ -52,6 +52,7 @@ import android.widget.TextView; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.TrafficStatsConstants; import java.io.IOException; import java.lang.reflect.Field; @@ -238,7 +239,8 @@ public class CaptivePortalLoginActivity extends Activity { if (isFinishing() || isDestroyed()) return; HttpURLConnection urlConnection = null; int httpResponseCode = 500; - int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE); + int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_PROBE); try { urlConnection = (HttpURLConnection) mNetwork.openConnection( new URL(mCm.getCaptivePortalServerUrl())); diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index 1544adb23175..b2baff5db75b 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -272,6 +272,9 @@ public class Assistant extends NotificationAssistantService { final int importance = entry.getImportance() < IMPORTANCE_LOW ? entry.getImportance() : IMPORTANCE_LOW; signals.putInt(KEY_IMPORTANCE, importance); + } else { + // Even if no change is made, send an identity adjustment for metric logging. + signals.putInt(KEY_IMPORTANCE, entry.getImportance()); } } diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java index 64adc0d48309..af0e3bb8bfc2 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java @@ -65,6 +65,7 @@ import com.android.internal.util.HexDump; import com.android.internal.util.MessageUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.internal.util.TrafficStatsConstants; import com.android.internal.util.WakeupMessage; import java.io.FileDescriptor; @@ -329,7 +330,8 @@ public class DhcpClient extends StateMachine { } private boolean initUdpSocket() { - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_DHCP); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_DHCP); try { mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); SocketUtils.bindSocketToInterface(mUdpSock, mIfaceName); diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java index 8832eaadf6cb..d21b5f7853bb 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java @@ -16,7 +16,6 @@ package android.net.dhcp; -import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; import static android.net.dhcp.DhcpPacket.DHCP_SERVER; @@ -33,6 +32,7 @@ import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_BROADCAST; import static android.system.OsConstants.SO_REUSEADDR; +import static com.android.internal.util.TrafficStatsConstants.TAG_SYSTEM_DHCP_SERVER; import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE; import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL; import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY; diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 2a612503620f..27d420328017 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -98,6 +98,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.RingBufferIndices; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.internal.util.TrafficStatsConstants; import com.android.networkstack.R; import com.android.networkstack.metrics.DataStallDetectionStats; import com.android.networkstack.metrics.DataStallStatsUtils; @@ -1478,7 +1479,8 @@ public class NetworkMonitor extends StateMachine { int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE; String redirectUrl = null; final Stopwatch probeTimer = new Stopwatch().start(); - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_PROBE); try { urlConnection = (HttpURLConnection) mNetwork.openConnection(url); urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC); diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING new file mode 100644 index 000000000000..42aa47cab154 --- /dev/null +++ b/packages/PackageInstaller/TEST_MAPPING @@ -0,0 +1,24 @@ +{ + "presubmit": [ + { + "name": "CtsPackageInstallTestCases", + "options": [ + { + "exclude-annotation": "android.platform.test.annotations.AppModeInstant" + } + ] + }, + { + "name": "CtsNoPermissionTestCases" + }, + { + "name": "CtsNoPermissionTestCases25" + }, + { + "name": "CtsPackageInstallerTapjackingTestCases" + }, + { + "name": "CtsPackageUninstallTestCases" + } + ] +}
\ No newline at end of file diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java index cee4666a39ba..93f24f7881a6 100755 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java @@ -83,28 +83,6 @@ public class InstallInstalling extends AlertActivity { ApplicationInfo appInfo = getIntent() .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mPackageURI = getIntent().getData(); - final File sourceFile = new File(mPackageURI.getPath()); - PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); - - mAlert.setIcon(as.icon); - mAlert.setTitle(as.label); - mAlert.setView(R.layout.install_content_view); - mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel), - (ignored, ignored2) -> { - if (mInstallingTask != null) { - mInstallingTask.cancel(true); - } - - if (mSessionId > 0) { - getPackageManager().getPackageInstaller().abandonSession(mSessionId); - mSessionId = 0; - } - - setResult(RESULT_CANCELED); - finish(); - }, null); - setupAlert(); - requireViewById(R.id.installing).setVisibility(View.VISIBLE); if ("package".equals(mPackageURI.getScheme())) { try { @@ -114,6 +92,29 @@ public class InstallInstalling extends AlertActivity { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } else { + final File sourceFile = new File(mPackageURI.getPath()); + PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); + + mAlert.setIcon(as.icon); + mAlert.setTitle(as.label); + mAlert.setView(R.layout.install_content_view); + mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel), + (ignored, ignored2) -> { + if (mInstallingTask != null) { + mInstallingTask.cancel(true); + } + + if (mSessionId > 0) { + getPackageManager().getPackageInstaller().abandonSession(mSessionId); + mSessionId = 0; + } + + setResult(RESULT_CANCELED); + finish(); + }, null); + setupAlert(); + requireViewById(R.id.installing).setVisibility(View.VISIBLE); + if (savedInstanceState != null) { mSessionId = savedInstanceState.getInt(SESSION_ID); mInstallId = savedInstanceState.getInt(INSTALL_ID); diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java index f2de9ecd8f5d..881f4b183f40 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java @@ -109,8 +109,8 @@ public class InstallStart extends Activity { } else { Uri packageUri = intent.getData(); - if (packageUri != null && (packageUri.getScheme().equals(ContentResolver.SCHEME_FILE) - || packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT))) { + if (packageUri != null && packageUri.getScheme().equals( + ContentResolver.SCHEME_CONTENT)) { // [IMPORTANT] This path is deprecated, but should still work. Only necessary // features should be added. diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java index 87b5b57c7d9e..4f4aef0b0fae 100644 --- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java +++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java @@ -76,11 +76,13 @@ public class RestrictedLockUtils { public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) { final Intent intent = getShowAdminSupportDetailsIntent(context, admin); int targetUserId = UserHandle.myUserId(); - if (admin != null && admin.user != null - && isCurrentUserOrProfile(context, admin.user.getIdentifier())) { - targetUserId = admin.user.getIdentifier(); + if (admin != null) { + if (admin.user != null + && isCurrentUserOrProfile(context, admin.user.getIdentifier())) { + targetUserId = admin.user.getIdentifier(); + } + intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction); } - intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction); context.startActivityAsUser(intent, UserHandle.of(targetUserId)); } diff --git a/packages/SettingsLib/res/layout/settings_dialog_title.xml b/packages/SettingsLib/res/layout/settings_dialog_title.xml new file mode 100644 index 000000000000..1e065e0dbb4d --- /dev/null +++ b/packages/SettingsLib/res/layout/settings_dialog_title.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/settings_title_panel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/settings_title_template" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="center" + android:paddingStart="?android:attr/dialogPreferredPadding" + android:paddingEnd="?android:attr/dialogPreferredPadding" + android:paddingTop="@*android:dimen/dialog_padding_top_material"> + + <ImageView + android:id="@+id/settings_icon" + android:layout_width="24dip" + android:layout_height="24dip" + android:layout_marginBottom="12dip" /> + + <TextView + android:id="@+id/settings_title" + android:singleLine="true" + android:ellipsize="end" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAlignment="center" + style="?android:attr/windowTitleStyle" /> + </LinearLayout> + + <Space + android:id="@+id/settings_title_divider" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="@*android:dimen/dialog_title_divider_material" /> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt index 239b1d464ea3..eff02d24431e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt +++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt @@ -173,6 +173,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) } override fun draw(c: Canvas) { + c.saveLayer(null, null) unifiedPath.reset() levelPath.reset() levelRect.set(fillRect) @@ -243,6 +244,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) // And draw the plus sign on top of the fill c.drawPath(scaledPlus, errorPaint) } + c.restore() } private fun batteryColorForLevel(level: Int): Int { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java index 2b5a4e069001..11c799ea9df5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java @@ -16,6 +16,7 @@ package com.android.settingslib; +import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT; @@ -28,11 +29,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.UserHandle; @@ -42,6 +45,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -283,6 +287,26 @@ public class RestrictedLockUtilsTest { assertThat(profile).isNull(); } + @Test + public void sendShowAdminSupportDetailsIntent_extraRestrictionProvided() { + EnforcedAdmin enforcedAdmin = new EnforcedAdmin(); + enforcedAdmin.enforcedRestriction = "Dummy"; + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, enforcedAdmin); + + ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivityAsUser(intentCaptor.capture(), any()); + assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Dummy"); + } + + @Test + public void sendShowAdminSupportDetailsIntent_noExtraRestriction() { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, null); + + ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivityAsUser(intentCaptor.capture(), any()); + assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isNull(); + } + private UserInfo setUpUser(int userId, ComponentName[] admins) { UserInfo userInfo = new UserInfo(userId, "primary", 0); when(mUserManager.getUserInfo(userId)).thenReturn(userInfo); diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png Binary files differindex 83d714bfcb05..83d714bfcb05 100644 --- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_thumbnail.png +++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png Binary files differdeleted file mode 100644 index 2bfd655e37de..000000000000 --- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png +++ /dev/null diff --git a/packages/SystemUI/res-keyguard/drawable/analog_frame.xml b/packages/SystemUI/res-keyguard/drawable/analog_frame.xml new file mode 100644 index 000000000000..a663ac826127 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/analog_frame.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="250dp" + android:width="250dp" + android:viewportHeight="380" + android:viewportWidth="380"> + <path android:fillColor="#000000" android:pathData="M190,190m0,2a2,2 0,1 1,0 -4a2,2 0,1 1,0 4"/> +</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml new file mode 100644 index 000000000000..c7b6d60b319f --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="250dp" + android:width="250dp" + android:viewportHeight="380" + android:viewportWidth="380"> + <path android:fillColor="#777777" android:fillType="evenOdd" android:pathData="M203,190C203,185.398 200.608,181.354 197,179.044L197,58C197,54.134 193.866,51 190,51C186.134,51 183,54.134 183,58L183,179.043C179.392,181.354 177,185.397 177,190C177,197.18 182.82,203 190,203C197.18,203 203,197.18 203,190Z"/> +</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml new file mode 100644 index 000000000000..458275bec23a --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="250dp" + android:width="250dp" + android:viewportHeight="380" + android:viewportWidth="380"> + <path android:fillColor="#FFFFFF" android:pathData="M192,182.252C195.45,183.14 198,186.272 198,190C198,194.418 194.418,198 190,198C185.582,198 182,194.418 182,190C182,186.272 184.55,183.14 188,182.252L188,10C188,8.895 188.895,8 190,8C191.105,8 192,8.895 192,10L192,182.252Z"/> +</vector> diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/analog_clock.xml index dd25df864733..cf6d35ee27af 100644 --- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml +++ b/packages/SystemUI/res-keyguard/layout/analog_clock.xml @@ -35,9 +35,27 @@ android:format24Hour="@string/keyguard_widget_24_hours_format" android:elegantTextHeight="false" /> - <com.android.keyguard.clock.StretchAnalogClock + <com.android.keyguard.clock.ImageClock android:id="@+id/analog_clock" - android:layout_width="match_parent" - android:layout_height="match_parent" - /> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + > + <ImageView + android:id="@+id/hour_hand" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/analog_hour_hand" + /> + <ImageView + android:id="@+id/minute_hand" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/analog_minute_hand" + /> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/analog_frame" + /> + </com.android.keyguard.clock.ImageClock> </com.android.keyguard.clock.ClockLayout> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 4738887d546e..1e98189fa238 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -413,9 +413,6 @@ number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. <string name="clock_title_bubble" translatable="false">Bubble</string> <!-- Title for Stretch clock face that will appear in the picker app next to a preview image of the clock face. [CHAR LIMIT=8] --> - <string name="clock_title_stretch" translatable="false">Stretch</string> - <!-- Title for Typographic clock face that will appear in the picker app next to a preview image of - the clock face. [CHAR LIMIT=8] --> - <string name="clock_title_type" translatable="false">Type</string> + <string name="clock_title_analog" translatable="false">Analog</string> </resources> diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml index f34161e285da..81d44cfa49dd 100644 --- a/packages/SystemUI/res/layout/qs_tile_label.xml +++ b/packages/SystemUI/res/layout/qs_tile_label.xml @@ -44,8 +44,7 @@ android:padding="0dp" android:gravity="center" android:ellipsize="marquee" - android:textAppearance="@style/TextAppearance.QS.TileLabel" - android:textColor="?android:attr/textColorPrimary"/> + android:textAppearance="@style/TextAppearance.QS.TileLabel"/> <ImageView android:id="@+id/restricted_padlock" android:layout_width="@dimen/qs_tile_text_size" diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index fa39ccd28ff1..1d19fecac8c9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -665,9 +665,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { boolean wasRunning = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING; boolean isRunning = fingerprintRunningState == BIOMETRIC_STATE_RUNNING; mFingerprintRunningState = fingerprintRunningState; - if (DEBUG) Log.v(TAG, "Fingerprint State: " + mFingerprintRunningState); + Log.d(TAG, "fingerprintRunningState: " + mFingerprintRunningState); // Clients of KeyguardUpdateMonitor don't care about the internal state about the - // asynchronousness of the cancel cycle. So only notify them if the actualy running state + // asynchronousness of the cancel cycle. So only notify them if the actually running state // has changed. if (wasRunning != isRunning) { notifyFingerprintRunningStateChanged(); @@ -818,9 +818,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { boolean wasRunning = mFaceRunningState == BIOMETRIC_STATE_RUNNING; boolean isRunning = faceRunningState == BIOMETRIC_STATE_RUNNING; mFaceRunningState = faceRunningState; - if (DEBUG) Log.v(TAG, "Face State: " + mFaceRunningState); + Log.d(TAG, "faceRunningState: " + mFaceRunningState); // Clients of KeyguardUpdateMonitor don't care about the internal state or about the - // asynchronousness of the cancel cycle. So only notify them if the actualy running state + // asynchronousness of the cancel cycle. So only notify them if the actually running state // has changed. if (wasRunning != isRunning) { notifyFaceRunningStateChanged(); @@ -1665,7 +1665,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } mFaceCancelSignal = new CancellationSignal(); mFaceManager.authenticate(null, mFaceCancelSignal, 0, - mFaceAuthenticationCallback, null); + mFaceAuthenticationCallback, null, userId); setFaceRunningState(BIOMETRIC_STATE_RUNNING); } } @@ -2045,7 +2045,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { */ public void onKeyguardVisibilityChanged(boolean showing) { checkIsHandlerThread(); - if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); + Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); mKeyguardIsVisible = showing; for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java index 81b6a600f398..1652121f350d 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java @@ -35,7 +35,7 @@ import java.util.TimeZone; /** * Controller for Stretch clock that can appear on lock screen and AOD. */ -public class StretchAnalogClockController implements ClockPlugin { +public class AnalogClockController implements ClockPlugin { /** * Resources used to get title and thumbnail. @@ -60,9 +60,9 @@ public class StretchAnalogClockController implements ClockPlugin { /** * Custom clock shown on AOD screen and behind stack scroller on lock. */ - private View mBigClockView; + private ClockLayout mBigClockView; private TextClock mDigitalClock; - private StretchAnalogClock mAnalogClock; + private ImageClock mAnalogClock; /** * Small clock shown on lock screen above stack scroller. @@ -82,7 +82,7 @@ public class StretchAnalogClockController implements ClockPlugin { * @param inflater Inflater used to inflate custom clock views. * @param colorExtractor Extracts accent color from wallpaper. */ - public StretchAnalogClockController(Resources res, LayoutInflater inflater, + public AnalogClockController(Resources res, LayoutInflater inflater, SysuiColorExtractor colorExtractor) { mResources = res; mLayoutInflater = inflater; @@ -90,7 +90,7 @@ public class StretchAnalogClockController implements ClockPlugin { } private void createViews() { - mBigClockView = mLayoutInflater.inflate(R.layout.stretchanalog_clock, null); + mBigClockView = (ClockLayout) mLayoutInflater.inflate(R.layout.analog_clock, null); mAnalogClock = mBigClockView.findViewById(R.id.analog_clock); mDigitalClock = mBigClockView.findViewById(R.id.digital_clock); @@ -114,17 +114,17 @@ public class StretchAnalogClockController implements ClockPlugin { @Override public String getName() { - return "stretch"; + return "analog"; } @Override public String getTitle() { - return mResources.getString(R.string.clock_title_stretch); + return mResources.getString(R.string.clock_title_analog); } @Override public Bitmap getThumbnail() { - return BitmapFactory.decodeResource(mResources, R.drawable.stretch_thumbnail); + return BitmapFactory.decodeResource(mResources, R.drawable.analog_thumbnail); } @Override @@ -175,13 +175,14 @@ public class StretchAnalogClockController implements ClockPlugin { } final int length = colorPalette.length; mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 5)]); - mAnalogClock.setClockColor(colorPalette[Math.max(0, length - 5)], + mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 5)], colorPalette[Math.max(0, length - 2)]); } @Override public void onTimeTick() { mAnalogClock.onTimeChanged(); + mBigClockView.onTimeChanged(); mDigitalClock.refresh(); mLockClock.refresh(); } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java index d30f45f212b9..6069a5e4783d 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java @@ -60,7 +60,7 @@ public class BubbleClockController implements ClockPlugin { /** * Custom clock shown on AOD screen and behind stack scroller on lock. */ - private View mView; + private ClockLayout mView; private TextClock mDigitalClock; private ImageClock mAnalogClock; @@ -90,7 +90,7 @@ public class BubbleClockController implements ClockPlugin { } private void createViews() { - mView = mLayoutInflater.inflate(R.layout.bubble_clock, null); + mView = (ClockLayout) mLayoutInflater.inflate(R.layout.bubble_clock, null); mDigitalClock = (TextClock) mView.findViewById(R.id.digital_clock); mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock); @@ -186,6 +186,7 @@ public class BubbleClockController implements ClockPlugin { @Override public void onTimeTick() { mAnalogClock.onTimeChanged(); + mView.onTimeChanged(); mDigitalClock.refresh(); mLockClock.refresh(); } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java index 7ffee5d5232d..55088a800ec8 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java @@ -32,6 +32,7 @@ import com.android.keyguard.R; */ public class ClockLayout extends FrameLayout { + private static final int ANALOG_CLOCK_SHIFT_FACTOR = 3; /** * Clock face views. */ @@ -73,7 +74,14 @@ public class ClockLayout extends FrameLayout { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); + positionChildren(); + } + + void onTimeChanged() { + positionChildren(); + } + private void positionChildren() { final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX * 2, true) - mBurnInPreventionOffsetX; final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY * 2, false) @@ -89,9 +97,9 @@ public class ClockLayout extends FrameLayout { // Put the analog clock in the middle of the screen. if (mAnalogClock != null) { mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth())) - + offsetX); + + ANALOG_CLOCK_SHIFT_FACTOR * offsetX); mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight())) - + offsetY); + + ANALOG_CLOCK_SHIFT_FACTOR * offsetY); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java index e373ca1d955c..06488b86c59e 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java @@ -142,8 +142,7 @@ public final class ClockManager { addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor)); addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor)); - addBuiltinClock(() -> new StretchAnalogClockController(res, layoutInflater, - colorExtractor)); + addBuiltinClock(() -> new AnalogClockController(res, layoutInflater, colorExtractor)); // Store the size of the display for generation of clock preview. DisplayMetrics dm = res.getDisplayMetrics(); diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java deleted file mode 100644 index 8cdd6325638e..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.keyguard.clock; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.view.View; - -import java.util.Calendar; -import java.util.TimeZone; - -/** - * Analog clock where the minute hand extends off of the screen. - */ -public class StretchAnalogClock extends View { - - private static final int DEFAULT_COLOR = Color.parseColor("#F5C983"); - private static final float HOUR_STROKE_WIDTH = 60f; - private static final float MINUTE_STROKE_WIDTH = 20f; - private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 80f; - - private final Paint mHourPaint = new Paint(); - private final Paint mMinutePaint = new Paint(); - private Calendar mTime = Calendar.getInstance(TimeZone.getDefault()); - private TimeZone mTimeZone; - - public StretchAnalogClock(Context context) { - this(context, null); - } - - public StretchAnalogClock(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(); - } - - /** - * Call when the time changes to update the clock hands. - */ - public void onTimeChanged() { - mTime.setTimeInMillis(System.currentTimeMillis()); - invalidate(); - } - - /** - * Call when the time zone has changed to update clock hands. - * - * @param timeZone The updated time zone that will be used. - */ - public void onTimeZoneChanged(TimeZone timeZone) { - mTime.setTimeZone(timeZone); - } - - /** - * Set the colors to use on the clock face. - * @param dark Darker color obtained from color palette. - * @param light Lighter color obtained from color palette. - */ - public void setClockColor(int dark, int light) { - mHourPaint.setColor(dark); - invalidate(); - } - - private void init() { - mHourPaint.setColor(DEFAULT_COLOR); - mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH); - mHourPaint.setAntiAlias(true); - mHourPaint.setStrokeCap(Paint.Cap.ROUND); - - mMinutePaint.setColor(Color.WHITE); - mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH); - mMinutePaint.setAntiAlias(true); - mMinutePaint.setStrokeCap(Paint.Cap.ROUND); - } - - @Override - protected void onDraw(Canvas canvas) { - final float centerX = getWidth() / 2f; - final float centerY = getHeight() / 2f; - - final float minutesRotation = mTime.get(Calendar.MINUTE) * 6f; - final float hoursRotation = mTime.get(Calendar.HOUR) * 30 - + mTime.get(Calendar.MINUTE) * 0.5f; - - // Compute length of clock hands. Hour hand is 60% the length from center to edge - // and minute hand is twice the length to make sure it extends past screen edge. - double sMinuteHandLengthFactor = Math.sin(2d * Math.PI * minutesRotation / 360d); - float sMinuteHandLength = (float) (2d * (centerY + (centerX - centerY) - * sMinuteHandLengthFactor * sMinuteHandLengthFactor)); - double sHourHandLengthFactor = Math.sin(2d * Math.PI * hoursRotation / 360d); - float sHourHandLength = (float) (0.6d * (centerY + (centerX - centerY) - * sHourHandLengthFactor * sHourHandLengthFactor)); - - canvas.save(); - - canvas.rotate(minutesRotation, centerX, centerY); - canvas.drawLine( - centerX, - centerY + CENTER_GAP_AND_CIRCLE_RADIUS, - centerX, - centerY - sMinuteHandLength, - mMinutePaint); - - canvas.rotate(hoursRotation - minutesRotation, centerX, centerY); - canvas.drawLine( - centerX, - centerY + CENTER_GAP_AND_CIRCLE_RADIUS, - centerX, - centerY - sHourHandLength, - mHourPaint); - - canvas.restore(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mTime.setTimeZone(mTimeZone != null ? mTimeZone : TimeZone.getDefault()); - onTimeChanged(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 329b001a0a7c..6c1d1f91830f 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -180,10 +180,6 @@ public class BatteryMeterView extends LinearLayout implements setClipChildren(false); setClipToPadding(false); Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this); - - // Needed for PorderDuff.Mode.CLEAR operations to work properly, but redraws don't happen - // enough to justify a hardware layer. - setLayerType(LAYER_TYPE_SOFTWARE, null); } private void setupLayoutTransition() { @@ -405,10 +401,10 @@ public class BatteryMeterView extends LinearLayout implements || mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) { if (!showing) { mBatteryPercentView = loadPercentView(); - if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); if (mPercentageStyleId != 0) { // Only set if specified as attribute mBatteryPercentView.setTextAppearance(mPercentageStyleId); } + if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); updatePercentText(); addView(mBatteryPercentView, new ViewGroup.LayoutParams( diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index 665df777c1c1..03324777e4ea 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -16,47 +16,65 @@ package com.android.systemui.bubbles; +import android.os.UserHandle; import android.view.LayoutInflater; import com.android.systemui.R; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import java.util.Objects; + /** * Encapsulates the data and UI elements of a bubble. */ class Bubble { + private static final boolean DEBUG = false; + private static final String TAG = "Bubble"; + private final String mKey; + private final String mGroupId; private final BubbleExpandedView.OnBubbleBlockedListener mListener; private boolean mInflated; - - public BubbleView iconView; - public BubbleExpandedView expandedView; public NotificationEntry entry; + BubbleView iconView; + BubbleExpandedView expandedView; + + private static String groupId(NotificationEntry entry) { + UserHandle user = entry.notification.getUser(); + return user.getIdentifier() + '|' + entry.notification.getPackageName(); + } Bubble(NotificationEntry e, BubbleExpandedView.OnBubbleBlockedListener listener) { entry = e; mKey = e.key; + mGroupId = groupId(e); mListener = listener; } - /** @deprecated use the other constructor to defer View creation. */ - @Deprecated - Bubble(NotificationEntry e, LayoutInflater inflater, BubbleStackView stackView, - BubbleExpandedView.OnBubbleBlockedListener listener) { - this(e, listener); - inflate(inflater, stackView); - } - public String getKey() { return mKey; } + public String getGroupId() { + return mGroupId; + } + + public String getPackageName() { + return entry.notification.getPackageName(); + } + boolean isInflated() { return mInflated; } + public void updateDotVisibility() { + if (iconView != null) { + iconView.updateDotVisibility(); + } + } + void inflate(LayoutInflater inflater, BubbleStackView stackView) { if (mInflated) { return; @@ -73,10 +91,32 @@ class Bubble { mInflated = true; } + void setDismissed() { + entry.setBubbleDismissed(true); + // TODO: move this somewhere where it can be guaranteed not to run until safe from flicker + if (expandedView != null) { + expandedView.cleanUpExpandedState(); + } + } + void setEntry(NotificationEntry entry) { + this.entry = entry; if (mInflated) { iconView.update(entry); expandedView.update(entry); } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Bubble)) return false; + Bubble bubble = (Bubble) o; + return Objects.equals(mKey, bubble.mKey); + } + + @Override + public int hashCode() { + return Objects.hash(mKey); + } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 0fcc9501e367..acdcfb2ea688 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -77,8 +77,7 @@ import javax.inject.Singleton; * The controller manages addition, removal, and visible state of bubbles on screen. */ @Singleton -public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener, - ConfigurationController.ConfigurationListener { +public class BubbleController implements ConfigurationController.ConfigurationListener { private static final String TAG = "BubbleController"; @@ -174,6 +173,10 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe @Override public void onStateChanged(int newState) { mState = newState; + boolean shouldCollapse = (mState != SHADE); + if (shouldCollapse) { + collapseStack(); + } updateVisibility(); } } @@ -236,7 +239,6 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe if (mExpandListener != null) { mStackView.setExpandListener(mExpandListener); } - mStackView.setOnBlockedListener(this); } } @@ -284,28 +286,38 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe if (mStackView == null) { return false; } - for (Bubble bubble : mBubbleData.getBubbles()) { - if (!bubble.entry.isBubbleDismissed()) { - return true; - } - } - return false; + return mBubbleData.hasBubbles(); } /** * Whether the stack of bubbles is expanded or not. */ public boolean isStackExpanded() { - return mStackView != null && mStackView.isExpanded(); + return mBubbleData.isExpanded(); + } + + /** + * Tell the stack of bubbles to expand. + */ + public void expandStack() { + mBubbleData.setExpanded(true); } /** * Tell the stack of bubbles to collapse. */ public void collapseStack() { - if (mStackView != null) { - mStackView.collapseStack(); - } + mBubbleData.setExpanded(false /* expanded */); + } + + void selectBubble(Bubble bubble) { + mBubbleData.setSelectedBubble(bubble); + } + + @VisibleForTesting + void selectBubble(String key) { + Bubble bubble = mBubbleData.getBubbleWithKey(key); + selectBubble(bubble); } /** @@ -314,8 +326,10 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe * @param notificationKey the notification key for the bubble to be selected */ public void expandStackAndSelectBubble(String notificationKey) { - if (mStackView != null && mBubbleData.getBubble(notificationKey) != null) { - mStackView.setExpandedBubble(notificationKey); + Bubble bubble = mBubbleData.getBubbleWithKey(notificationKey); + if (bubble != null) { + mBubbleData.setSelectedBubble(bubble); + mBubbleData.setExpanded(true); } } @@ -323,13 +337,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack. */ void dismissStack(@DismissReason int reason) { - if (mStackView == null) { - return; - } - mStackView.stackDismissed(reason); - - updateVisibility(); - mNotificationEntryManager.updateNotifications(); + mBubbleData.dismissAll(reason); } /** @@ -348,20 +356,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe * @param notif the notification associated with this bubble. */ void updateBubble(NotificationEntry notif) { - if (mStackView != null && mBubbleData.getBubble(notif.key) != null) { - // It's an update - mStackView.updateBubble(notif); - } else { - // It's new - ensureStackViewCreated(); - mStackView.addBubble(notif); - } - Bubble bubble = mBubbleData.getBubble(notif.key); - if (shouldAutoExpand(notif)) { - mStackView.setSelectedBubble(bubble); - mStackView.setExpanded(true); - } - updateVisibility(); + mBubbleData.notificationEntryUpdated(notif); } /** @@ -371,23 +366,10 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe */ @MainThread void removeBubble(String key, int reason) { - if (mStackView != null) { - mStackView.removeBubble(key, reason); - } - mNotificationEntryManager.updateNotifications(); - updateVisibility(); - } - - @Override - public void onBubbleBlocked(NotificationEntry entry) { - Object[] bubbles = mBubbleData.getBubbles().toArray(); - for (int i = 0; i < bubbles.length; i++) { - NotificationEntry e = ((Bubble) bubbles[i]).entry; - boolean samePackage = entry.notification.getPackageName().equals( - e.notification.getPackageName()); - if (samePackage) { - removeBubble(entry.key, DISMISS_BLOCKED); - } + // TEMP: refactor to change this to pass entry + Bubble bubble = mBubbleData.getBubbleWithKey(key); + if (bubble != null) { + mBubbleData.notificationEntryRemoved(bubble.entry, reason); } } @@ -424,7 +406,6 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe updateShowInShadeForSuppressNotification(entry); entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed updateBubble(entry); - mStackView.updateDotVisibility(entry.key); } } @@ -446,44 +427,57 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe } }; + @SuppressWarnings("FieldCanBeLocal") private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() { + @Override public void onBubbleAdded(Bubble bubble) { - + ensureStackViewCreated(); + mStackView.addBubble(bubble); } @Override public void onBubbleRemoved(Bubble bubble, int reason) { - + if (mStackView != null) { + mStackView.removeBubble(bubble); + } } public void onBubbleUpdated(Bubble bubble) { - + if (mStackView != null) { + mStackView.updateBubble(bubble); + } } @Override public void onOrderChanged(List<Bubble> bubbles) { - } @Override public void onSelectionChanged(Bubble selectedBubble) { - + if (mStackView != null) { + mStackView.setSelectedBubble(selectedBubble); + } } @Override public void onExpandedChanged(boolean expanded) { - + if (mStackView != null) { + mStackView.setExpanded(expanded); + } } @Override public void showFlyoutText(Bubble bubble, String text) { - + if (mStackView != null) { + mStackView.animateInFlyoutForBubble(bubble); + } } @Override public void apply() { - + mNotificationEntryManager.updateNotifications(); + updateVisibility(); } }; @@ -514,7 +508,6 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe mStackView.setVisibility(hasBubbles() ? VISIBLE : INVISIBLE); } else if (mStackView != null) { mStackView.setVisibility(INVISIBLE); - collapseStack(); } updateBubblesShowing(); } @@ -621,14 +614,14 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe @Override public void onTaskMovedToFront(RunningTaskInfo taskInfo) { if (mStackView != null && taskInfo.displayId == Display.DEFAULT_DISPLAY) { - mStackView.collapseStack(); + mBubbleData.setExpanded(false); } } @Override public void onActivityLaunchOnSecondaryDisplayRerouted() { if (mStackView != null) { - mStackView.collapseStack(); + mBubbleData.setExpanded(false); } } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index fe3f9d192cd5..259665dedf5b 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -15,14 +15,24 @@ */ package com.android.systemui.bubbles; -import androidx.annotation.Nullable; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; + +import android.app.ActivityManager; +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.bubbles.BubbleController.DismissReason; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; +import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.Objects; import javax.inject.Inject; import javax.inject.Singleton; @@ -33,6 +43,8 @@ import javax.inject.Singleton; @Singleton public class BubbleData { + private static final String TAG = "BubbleData"; + /** * This interface reports changes to the state and appearance of bubbles which should be applied * as necessary to the UI. @@ -53,7 +65,7 @@ public class BubbleData { * A Bubble has been removed. A call to {@link #onOrderChanged(List)} will * follow. */ - void onBubbleRemoved(Bubble bubble, @BubbleController.DismissReason int reason); + void onBubbleRemoved(Bubble bubble, @DismissReason int reason); /** * An existing bubble has been updated. @@ -86,46 +98,253 @@ public class BubbleData { void apply(); } - private HashMap<String, Bubble> mBubbles = new HashMap<>(); + private final Context mContext; + private final List<Bubble> mBubbles = new ArrayList<>(); + private Bubble mSelectedBubble; + private boolean mExpanded; private Listener mListener; @VisibleForTesting @Inject - public BubbleData() {} + public BubbleData(Context context) { + mContext = context; + } + + public boolean hasBubbles() { + return !mBubbles.isEmpty(); + } + + public boolean isExpanded() { + return mExpanded; + } + + public boolean hasBubbleWithKey(String key) { + return getBubbleWithKey(key) != null; + } + + public void setExpanded(boolean expanded) { + if (setExpandedInternal(expanded)) { + mListener.apply(); + } + } + + public void setSelectedBubble(Bubble bubble) { + if (setSelectedBubbleInternal(bubble)) { + mListener.apply(); + } + } + + public void notificationEntryUpdated(NotificationEntry entry) { + Bubble bubble = getBubbleWithKey(entry.key); + if (bubble == null) { + // Create a new bubble + bubble = new Bubble(entry, this::onBubbleBlocked); + mBubbles.add(0, bubble); // TODO: reorder/group + mListener.onBubbleAdded(bubble); + } else { + // Updates an existing bubble + bubble.setEntry(entry); + mListener.onBubbleUpdated(bubble); + } + if (shouldAutoExpand(entry)) { + setSelectedBubbleInternal(bubble); + if (!mExpanded) { + setExpandedInternal(true); + } + } else if (mSelectedBubble == null) { + setSelectedBubbleInternal(bubble); + } + // TODO: reorder/group + mListener.apply(); + } + + public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) { + int indexToRemove = indexForKey(entry.key); + if (indexToRemove >= 0) { + Bubble removed = mBubbles.remove(indexToRemove); + removed.setDismissed(); + mListener.onBubbleRemoved(removed, reason); + maybeSendDeleteIntent(reason, removed.entry); + + if (mBubbles.isEmpty()) { + setExpandedInternal(false); + setSelectedBubbleInternal(null); + } else if (removed == mSelectedBubble) { + int newIndex = Math.min(indexToRemove, mBubbles.size() - 1); + Bubble newSelected = mBubbles.get(newIndex); + setSelectedBubbleInternal(newSelected); + } + // TODO: reorder/group + mListener.apply(); + } + } + + public void dismissAll(@DismissReason int reason) { + boolean changed = setExpandedInternal(false); + while (!mBubbles.isEmpty()) { + Bubble bubble = mBubbles.remove(0); + bubble.setDismissed(); + maybeSendDeleteIntent(reason, bubble.entry); + mListener.onBubbleRemoved(bubble, reason); + changed = true; + } + if (setSelectedBubbleInternal(null)) { + changed = true; + } + if (changed) { + // TODO: reorder/group + mListener.apply(); + } + } /** - * The set of bubbles. + * Requests a change to the selected bubble. Calls {@link Listener#onSelectionChanged} if + * the value changes. + * + * @param bubble the new selected bubble + * @return true if the state changed as a result */ - public Collection<Bubble> getBubbles() { - return mBubbles.values(); + private boolean setSelectedBubbleInternal(Bubble bubble) { + if (Objects.equals(bubble, mSelectedBubble)) { + return false; + } + if (bubble != null && !mBubbles.contains(bubble)) { + Log.e(TAG, "Cannot select bubble which doesn't exist!" + + " (" + bubble + ") bubbles=" + mBubbles); + return false; + } + if (mExpanded) { + // TODO: bubble.markAsActive() ? + bubble.entry.setShowInShadeWhenBubble(false); + } + mSelectedBubble = bubble; + mListener.onSelectionChanged(mSelectedBubble); + return true; + } + + + /** + * Requests a change to the expanded state. Calls {@link Listener#onExpandedChanged} if + * the value changes. + * + * @param shouldExpand the new requested state + * @return true if the state changed as a result + */ + private boolean setExpandedInternal(boolean shouldExpand) { + if (mExpanded == shouldExpand) { + return false; + } + if (shouldExpand) { + if (mBubbles.isEmpty()) { + Log.e(TAG, "Attempt to expand stack when empty!"); + return false; + } + if (mSelectedBubble == null) { + Log.e(TAG, "Attempt to expand stack without selected bubble!"); + return false; + } + // TODO: bubble.markAsActive() ? + mSelectedBubble.entry.setShowInShadeWhenBubble(false); + } + // TODO: reorder/regroup + mExpanded = shouldExpand; + mListener.onExpandedChanged(mExpanded); + return true; } - @Nullable - public Bubble getBubble(String key) { - return mBubbles.get(key); + private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) { + if (reason == BubbleController.DISMISS_USER_GESTURE) { + Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata(); + PendingIntent deleteIntent = bubbleMetadata != null + ? bubbleMetadata.getDeleteIntent() + : null; + if (deleteIntent != null) { + try { + deleteIntent.send(); + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, "Failed to send delete intent for bubble with key: " + entry.key); + } + } + } } - public void addBubble(Bubble b) { - mBubbles.put(b.getKey(), b); + private void onBubbleBlocked(NotificationEntry entry) { + boolean changed = false; + final String blockedPackage = entry.notification.getPackageName(); + for (Iterator<Bubble> i = mBubbles.iterator(); i.hasNext(); ) { + Bubble bubble = i.next(); + if (bubble.getPackageName().equals(blockedPackage)) { + i.remove(); + mListener.onBubbleRemoved(bubble, BubbleController.DISMISS_BLOCKED); + changed = true; + } + } + if (changed) { + // TODO: reorder/group + mListener.apply(); + } } - @Nullable - public Bubble removeBubble(String key) { - return mBubbles.remove(key); + private int indexForKey(String key) { + for (int i = 0; i < mBubbles.size(); i++) { + Bubble bubble = mBubbles.get(i); + if (bubble.getKey().equals(key)) { + return i; + } + } + return -1; } - public void updateBubble(String key, NotificationEntry newEntry) { - Bubble oldBubble = mBubbles.get(key); - if (oldBubble != null) { - oldBubble.setEntry(newEntry); + private Bubble removeBubbleWithKey(String key) { + for (int i = 0; i < mBubbles.size(); i++) { + Bubble bubble = mBubbles.get(i); + if (bubble.getKey().equals(key)) { + mBubbles.remove(i); + return bubble; + } } + return null; + } + + /** + * The set of bubbles. + * + * @deprecated + */ + @Deprecated + public Collection<Bubble> getBubbles() { + return Collections.unmodifiableList(mBubbles); } - public void clear() { - mBubbles.clear(); + @VisibleForTesting(visibility = PRIVATE) + Bubble getBubbleWithKey(String key) { + for (int i = 0; i < mBubbles.size(); i++) { + Bubble bubble = mBubbles.get(i); + if (bubble.getKey().equals(key)) { + return bubble; + } + } + return null; } public void setListener(Listener listener) { mListener = listener; } -} + + boolean shouldAutoExpand(NotificationEntry entry) { + Notification.BubbleMetadata metadata = entry.getBubbleMetadata(); + return metadata != null && metadata.getAutoExpandBubble() + && isForegroundApp(entry.notification.getPackageName()); + } + + /** + * Return true if the applications with the package name is running in foreground. + * + * @param pkgName application package name. + */ + boolean isForegroundApp(String pkgName) { + ActivityManager am = mContext.getSystemService(ActivityManager.class); + List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1 /* maxNum */); + return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 686edada1036..18b2e37e31ec 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -20,8 +20,6 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.annotation.NonNull; -import android.app.Notification; -import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; @@ -54,9 +52,7 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.ViewClippingUtil; -import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController.DismissReason; import com.android.systemui.bubbles.animation.ExpandedAnimationController; import com.android.systemui.bubbles.animation.PhysicsAnimationLayout; import com.android.systemui.bubbles.animation.StackAnimationController; @@ -359,14 +355,13 @@ public class BubbleStackView extends FrameLayout { } switch (action) { case AccessibilityNodeInfo.ACTION_DISMISS: - Dependency.get(BubbleController.class).dismissStack( - BubbleController.DISMISS_ACCESSIBILITY_ACTION); + mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION); return true; case AccessibilityNodeInfo.ACTION_COLLAPSE: - collapseStack(); + mBubbleData.setExpanded(false); return true; case AccessibilityNodeInfo.ACTION_EXPAND: - expandStack(); + mBubbleData.setExpanded(true); return true; } return false; @@ -393,9 +388,9 @@ public class BubbleStackView extends FrameLayout { * @param key the {@link NotificationEntry#key} associated with the bubble. */ public void updateDotVisibility(String key) { - Bubble b = mBubbleData.getBubble(key); + Bubble b = mBubbleData.getBubbleWithKey(key); if (b != null) { - b.iconView.updateDotVisibility(); + b.updateDotVisibility(); } } @@ -407,16 +402,6 @@ public class BubbleStackView extends FrameLayout { } /** - * Sets the listener to notify when a bubble is blocked. - */ - public void setOnBlockedListener(BubbleExpandedView.OnBubbleBlockedListener listener) { - mBlockedListener = listener; - for (Bubble b : mBubbleData.getBubbles()) { - b.expandedView.setOnBlockedListener(mBlockedListener); - } - } - - /** * Whether the stack of bubbles is expanded or not. */ public boolean isExpanded() { @@ -445,7 +430,7 @@ public class BubbleStackView extends FrameLayout { */ @Deprecated void setExpandedBubble(String key) { - Bubble bubbleToExpand = mBubbleData.getBubble(key); + Bubble bubbleToExpand = mBubbleData.getBubbleWithKey(key); if (bubbleToExpand != null) { setSelectedBubble(bubbleToExpand); bubbleToExpand.entry.setShowInShadeWhenBubble(false); @@ -466,11 +451,36 @@ public class BubbleStackView extends FrameLayout { } } + // via BubbleData.Listener + void addBubble(Bubble bubble) { + bubble.inflate(mInflater, this); + mBubbleContainer.addView(bubble.iconView, 0, + new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + ViewClippingUtil.setClippingDeactivated(bubble.iconView, true, mClippingParameters); + requestUpdate(); + logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED); + } + + // via BubbleData.Listener + void removeBubble(Bubble bubble) { + // Remove it from the views + int removedIndex = mBubbleContainer.indexOfChild(bubble.iconView); + mBubbleContainer.removeViewAt(removedIndex); + logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED); + } + + // via BubbleData.Listener + void updateBubble(Bubble bubble) { + requestUpdate(); + logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED); + } + /** * Changes the currently selected bubble. If the stack is already expanded, the newly selected * bubble will be shown immediately. This does not change the expanded state or change the * position of any bubble. */ + // via BubbleData.Listener public void setSelectedBubble(Bubble bubbleToSelect) { if (mExpandedBubble != null && mExpandedBubble.equals(bubbleToSelect)) { return; @@ -489,7 +499,8 @@ public class BubbleStackView extends FrameLayout { logBubbleEvent(previouslySelected, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); logBubbleEvent(bubbleToSelect, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); notifyExpansionChanged(previouslySelected.entry, false /* expanded */); - notifyExpansionChanged(bubbleToSelect.entry, true /* expanded */); + notifyExpansionChanged(bubbleToSelect == null ? null : bubbleToSelect.entry, + true /* expanded */); }); } } @@ -497,13 +508,15 @@ public class BubbleStackView extends FrameLayout { /** * Changes the expanded state of the stack. * - * @param expanded whether the bubble stack should appear expanded + * @param shouldExpand whether the bubble stack should appear expanded */ - public void setExpanded(boolean expanded) { - if (expanded == mIsExpanded) { + // via BubbleData.Listener + public void setExpanded(boolean shouldExpand) { + boolean wasExpanded = mIsExpanded; + if (shouldExpand == wasExpanded) { return; } - if (mIsExpanded) { + if (wasExpanded) { // Collapse the stack animateExpansion(false /* expand */); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); @@ -518,131 +531,17 @@ public class BubbleStackView extends FrameLayout { } /** - * Adds a bubble to the top of the stack. - * - * @param entry the notification to add to the stack of bubbles. - */ - void addBubble(NotificationEntry entry) { - Bubble b = new Bubble(entry, mInflater, this /* stackView */, mBlockedListener); - mBubbleData.addBubble(b); - - mBubbleContainer.addView(b.iconView, 0, - new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - ViewClippingUtil.setClippingDeactivated(b.iconView, true, mClippingParameters); - - requestUpdate(); - logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED); - - animateInFlyoutForBubble(b); - } - - /** - * Remove a bubble from the stack. - */ - void removeBubble(String key, int reason) { - Bubble b = mBubbleData.removeBubble(key); - if (b == null) { - return; - } - setBubbleDismissed(b, reason); - - // Remove it from the views - int removedIndex = mBubbleContainer.indexOfChild(b.iconView); - mBubbleContainer.removeViewAt(removedIndex); - - int bubbleCount = mBubbleContainer.getChildCount(); - if (bubbleCount == 0) { - // If no bubbles remain, collapse the entire stack. - collapseStack(); - return; - } else if (b.equals(mExpandedBubble)) { - // Was the current bubble just removed? - // If we have other bubbles and are expanded go to the next one or previous - // if the bubble removed was last - int nextIndex = bubbleCount > removedIndex ? removedIndex : bubbleCount - 1; - BubbleView expandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex); - if (mIsExpanded) { - setExpandedBubble(expandedBubble.getKey()); - } else { - mExpandedBubble = null; - } - } - // TODO: consider logging reason code - logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED); - } - - /** * Dismiss the stack of bubbles. + * @deprecated */ + @Deprecated void stackDismissed(int reason) { - for (Bubble bubble : mBubbleData.getBubbles()) { - setBubbleDismissed(bubble, reason); - } - mBubbleData.clear(); - collapseStack(); - mBubbleContainer.removeAllViews(); - mExpandedViewContainer.removeAllViews(); - // TODO: consider logging reason code + mBubbleData.dismissAll(reason); logBubbleEvent(null /* no bubble associated with bubble stack dismiss */, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED); } /** - * Marks the notification entry as dismissed & calls any delete intents for the bubble. - * - * <p>Note: This does not remove the Bubble from BubbleData. - * - * @param bubble the Bubble being dismissed - * @param reason code for the reason the dismiss was triggered - * @see BubbleController.DismissReason - */ - private void setBubbleDismissed(Bubble bubble, @DismissReason int reason) { - if (DEBUG) { - Log.d(TAG, "dismissBubble: " + bubble + " reason=" + reason); - } - bubble.entry.setBubbleDismissed(true); - bubble.expandedView.cleanUpExpandedState(); - - if (reason == BubbleController.DISMISS_USER_GESTURE) { - Notification.BubbleMetadata bubbleMetadata = bubble.entry.getBubbleMetadata(); - PendingIntent deleteIntent = bubbleMetadata != null - ? bubbleMetadata.getDeleteIntent() - : null; - if (deleteIntent != null) { - try { - deleteIntent.send(); - } catch (PendingIntent.CanceledException e) { - Log.w(TAG, "Failed to send delete intent for bubble with key: " - + (bubble.entry != null ? bubble.entry.key : " null entry")); - } - } - } - } - - /** - * Updates a bubble in the stack. - * @param entry the entry to update in the stack. - */ - public void updateBubble(NotificationEntry entry) { - Bubble b = mBubbleData.getBubble(entry.key); - mBubbleData.updateBubble(entry.key, entry); - - if (!mIsExpanded) { - // If alerting it gets promoted to top of the stack. - if (mBubbleContainer.indexOfChild(b.iconView) != 0) { - mBubbleContainer.moveViewTo(b.iconView, 0); - } - requestUpdate(); - animateInFlyoutForBubble(b /* bubble */); - } - if (mIsExpanded && entry.equals(mExpandedBubble.entry)) { - entry.setShowInShadeWhenBubble(false); - requestUpdate(); - } - logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED); - } - - /** * @return the view the touch event is on */ @Nullable @@ -670,7 +569,7 @@ public class BubbleStackView extends FrameLayout { return this; } - public View getFlyoutView() { + View getFlyoutView() { return mFlyout; } @@ -683,13 +582,8 @@ public class BubbleStackView extends FrameLayout { */ @Deprecated @MainThread - public void collapseStack() { - if (mIsExpanded) { - // TODO: Save opened bubble & move it to top of stack - animateExpansion(false /* shouldExpand */); - notifyExpansionChanged(mExpandedBubble.entry, mIsExpanded); - logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); - } + void collapseStack() { + mBubbleData.setExpanded(false); } /** @@ -712,12 +606,8 @@ public class BubbleStackView extends FrameLayout { */ @Deprecated @MainThread - public void expandStack() { - if (!mIsExpanded) { - String expandedBubbleKey = getBubbleAt(0).getKey(); - setExpandedBubble(expandedBubbleKey); - logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED); - } + void expandStack() { + mBubbleData.setExpanded(true); } /** @@ -926,6 +816,7 @@ public class BubbleStackView extends FrameLayout { mFlyout.removeCallbacks(mHideFlyout); mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER); }); + logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT); } } @@ -1097,7 +988,8 @@ public class BubbleStackView extends FrameLayout { * @param action the user interaction enum. */ private void logBubbleEvent(@Nullable Bubble bubble, int action) { - if (bubble == null) { + if (bubble == null || bubble.entry == null + || bubble.entry.notification == null) { StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, null /* package name */, null /* notification channel */, diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java index 21406e57ad7b..d935466757de 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java @@ -34,7 +34,6 @@ import static android.opengl.GLES20.glVertexAttribPointer; import android.graphics.Bitmap; import android.opengl.GLUtils; -import android.os.Build; import android.util.Log; import java.nio.ByteBuffer; @@ -196,58 +195,76 @@ class ImageGLWallpaper { glUniform1i(mUniTexture, 0); } + /** + * This method adjust s(x-axis), t(y-axis) texture coordinates + * to prevent the wallpaper from being stretched. + * The adjustment happens if either the width or height of the bitmap is larger than + * corresponding size of the surface. + * If both width and height are larger than corresponding size of the surface, + * the adjustment will happen at both s, t side. + * + * @param bitmapWidth The width of the bitmap. + * @param bitmapHeight The height of the bitmap. + * @param surfaceWidth The width of the surface. + * @param surfaceHeight The height of the surface. + * @param xOffset The offset amount along s axis. + * @param yOffset The offset amount along t axis. + */ void adjustTextureCoordinates(int bitmapWidth, int bitmapHeight, int surfaceWidth, int surfaceHeight, float xOffset, float yOffset) { - float ratioW = 1f; - float ratioH = 1f; - float rX = 0f; - float rY = 0f; - float[] coordinates = null; - - final boolean adjustWidth = bitmapWidth > surfaceWidth; - final boolean adjustHeight = bitmapHeight > surfaceHeight; - - if (adjustWidth || adjustHeight) { - coordinates = TEXTURES.clone(); - } - - if (adjustWidth) { - float x = (float) Math.round((bitmapWidth - surfaceWidth) * xOffset) / bitmapWidth; - ratioW = (float) surfaceWidth / bitmapWidth; - float referenceX = x + ratioW > 1f ? 1f - ratioW : x; + float[] coordinates = TEXTURES.clone(); + + if (bitmapWidth > surfaceWidth) { + // Calculate the new s pos in pixels. + float pixelS = (float) Math.round((bitmapWidth - surfaceWidth) * xOffset); + // Calculate the s pos in texture coordinate. + float coordinateS = pixelS / bitmapWidth; + // Calculate the percentage occupied by the surface width in bitmap width. + float surfacePercentageW = (float) surfaceWidth / bitmapWidth; + // Need also consider the case if bitmap height is smaller than surface height. + if (bitmapHeight < surfaceHeight) { + // We will narrow the surface percentage to keep aspect ratio. + surfacePercentageW *= (float) bitmapHeight / surfaceHeight; + } + // Determine the final s pos, also limit the legal s pos to prevent from out of range. + float s = coordinateS + surfacePercentageW > 1f ? 1f - surfacePercentageW : coordinateS; + // Traverse the s pos in texture coordinates array and adjust the s pos accordingly. for (int i = 0; i < coordinates.length; i += 2) { + // indices 2, 4 and 6 are the end of s coordinates. if (i == 2 || i == 4 || i == 6) { - coordinates[i] = Math.min(1f, referenceX + ratioW); + coordinates[i] = Math.min(1f, s + surfacePercentageW); } else { - coordinates[i] = referenceX; + coordinates[i] = s; } } - rX = referenceX; } - - if (adjustHeight) { - float y = (float) Math.round((bitmapHeight - surfaceHeight) * yOffset) / bitmapHeight; - ratioH = (float) surfaceHeight / bitmapHeight; - float referenceY = y + ratioH > 1f ? 1f - ratioH : y; + if (bitmapHeight > surfaceHeight) { + // Calculate the new t pos in pixels. + float pixelT = (float) Math.round((bitmapHeight - surfaceHeight) * yOffset); + // Calculate the t pos in texture coordinate. + float coordinateT = pixelT / bitmapHeight; + // Calculate the percentage occupied by the surface height in bitmap height. + float surfacePercentageH = (float) surfaceHeight / bitmapHeight; + // Need also consider the case if bitmap width is smaller than surface width. + if (bitmapWidth < surfaceWidth) { + // We will narrow the surface percentage to keep aspect ratio. + surfacePercentageH *= (float) bitmapWidth / surfaceWidth; + } + // Determine the final t pos, also limit the legal t pos to prevent from out of range. + float t = coordinateT + surfacePercentageH > 1f ? 1f - surfacePercentageH : coordinateT; + // Traverse the t pos in texture coordinates array and adjust the t pos accordingly. for (int i = 1; i < coordinates.length; i += 2) { + // indices 1, 3 and 11 are the end of t coordinates. if (i == 1 || i == 3 || i == 11) { - coordinates[i] = Math.min(1f, referenceY + ratioH); + coordinates[i] = Math.min(1f, t + surfacePercentageH); } else { - coordinates[i] = referenceY; + coordinates[i] = t; } } - rY = referenceY; } - if (adjustWidth || adjustHeight) { - if (Build.IS_DEBUGGABLE) { - Log.d(TAG, "adjustTextureCoordinates: sW=" + surfaceWidth + ", sH=" + surfaceHeight - + ", bW=" + bitmapWidth + ", bH=" + bitmapHeight - + ", rW=" + ratioW + ", rH=" + ratioH + ", rX=" + rX + ", rY=" + rY); - } - mTextureBuffer.put(coordinates); - mTextureBuffer.position(0); - } + mTextureBuffer.put(coordinates); + mTextureBuffer.position(0); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index 6f50baa53e38..4590470697ea 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -25,9 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.graphics.Rect; import android.graphics.Typeface; -import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.icu.text.DateFormat; import android.icu.text.DisplayContext; @@ -37,13 +35,8 @@ import android.os.Handler; import android.os.Trace; import android.provider.Settings; import android.service.notification.ZenModeConfig; -import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; -import android.text.style.DynamicDrawableSpan; -import android.text.style.ImageSpan; import android.text.style.StyleSpan; -import android.util.MathUtils; import androidx.core.graphics.drawable.IconCompat; import androidx.slice.Slice; @@ -205,9 +198,9 @@ public class KeyguardSliceProvider extends SliceProvider implements addMediaLocked(builder); } else { builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText)); - addNextAlarmLocked(builder); - addZenModeLocked(builder); } + addNextAlarmLocked(builder); + addZenModeLocked(builder); addPrimaryActionLocked(builder); slice = builder.build(); } @@ -221,32 +214,25 @@ public class KeyguardSliceProvider extends SliceProvider implements protected void addMediaLocked(ListBuilder listBuilder) { if (mMediaMetaData != null) { - SpannableStringBuilder builder = new SpannableStringBuilder(); - - Icon notificationIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon(); - if (notificationIcon != null) { - Drawable drawable = notificationIcon.loadDrawable(getContext()); - Rect mediaBounds = new Rect(0 /* left */, 0 /* top */, - drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - int iconHeaderSize = getContext().getResources() - .getDimensionPixelSize(R.dimen.header_icon_size); - MathUtils.fitRect(mediaBounds, iconHeaderSize); - drawable.setBounds(mediaBounds); - builder.append("# "); - builder.setSpan(new ImageSpan(drawable, DynamicDrawableSpan.ALIGN_CENTER), - 0 /* start */, 1 /* end */, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - } - CharSequence title = mMediaMetaData.getText(MediaMetadata.METADATA_KEY_TITLE); if (TextUtils.isEmpty(title)) { title = getContext().getResources().getString(R.string.music_controls_no_title); } - builder.append(title); - listBuilder.setHeader(new ListBuilder.HeaderBuilder(mHeaderUri).setTitle(builder)); + listBuilder.setHeader(new ListBuilder.HeaderBuilder(mHeaderUri).setTitle(title)); CharSequence album = mMediaMetaData.getText(MediaMetadata.METADATA_KEY_ARTIST); if (!TextUtils.isEmpty(album)) { - listBuilder.addRow(new RowBuilder(mMediaUri).setTitle(album)); + RowBuilder albumBuilder = new RowBuilder(mMediaUri); + albumBuilder.setTitle(album); + + Icon mediaIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon(); + IconCompat mediaIconCompat = mediaIcon == null ? null + : IconCompat.createFromIcon(getContext(), mediaIcon); + if (mediaIconCompat != null) { + albumBuilder.addEndItem(mediaIconCompat, ListBuilder.ICON_IMAGE); + } + + listBuilder.addRow(albumBuilder); } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index bb159a9ba2e8..ebc3a6adaeee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -91,6 +91,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { if (mLayoutOrientation != newConfig.orientation) { mLayoutOrientation = newConfig.orientation; setCurrentItem(0, false); + mPageToRestore = 0; } } @@ -101,6 +102,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { mLayoutDirection = layoutDirection; setAdapter(mAdapter); setCurrentItem(0, false); + mPageToRestore = 0; } } @@ -112,6 +114,17 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { super.setCurrentItem(item, smoothScroll); } + /** + * Obtains the current page number respecting RTL + */ + private int getCurrentPageNumber() { + int page = getCurrentItem(); + if (mLayoutDirection == LAYOUT_DIRECTION_RTL) { + page = mPages.size() - 1 - page; + } + return page; + } + @Override public void setListening(boolean listening) { if (mListening == listening) return; @@ -199,7 +212,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { // marquee. This will ensure that accessibility doesn't announce the TYPE_VIEW_SELECTED // event on any of the children. setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - int currentItem = isLayoutRtl() ? mPages.size() - 1 - getCurrentItem() : getCurrentItem(); + int currentItem = getCurrentPageNumber(); for (int i = 0; i < mPages.size(); i++) { mPages.get(i).setSelected(i == currentItem ? selected : false); } @@ -328,7 +341,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { public int getNumVisibleTiles() { if (mPages.size() == 0) return 0; - TilePage currentPage = mPages.get(getCurrentItem()); + TilePage currentPage = mPages.get(getCurrentPageNumber()); return currentPage.mRecords.size(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index 8e77851acc8a..ec2feba8291b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -213,7 +213,11 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha } else { // These tiles disappear when expanding firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0); translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff); - translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff + width); + + // xDiff is negative here and this makes it "more" negative + final int translationX = mQsPanel.isLayoutRtl() ? xDiff - width : xDiff + width; + translationXBuilder.addFloat(quickTileView, "translationX", 0, + translationX); } mQuickQsViews.add(tileView.getIconWithBackground()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java index 91cd65259d73..8a360ee2e4eb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java @@ -15,11 +15,10 @@ package com.android.systemui.qs.tileimpl; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.service.quicksettings.Tile; -import android.text.SpannableStringBuilder; import android.text.TextUtils; -import android.text.style.ForegroundColorSpan; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -27,6 +26,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.android.settingslib.Utils; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.plugins.qs.QSIconView; @@ -46,6 +46,8 @@ public class QSTileView extends QSTileBaseView { private ViewGroup mLabelContainer; private View mExpandIndicator; private View mExpandSpace; + private ColorStateList mColorLabelDefault; + private ColorStateList mColorLabelUnavailable; public QSTileView(Context context, QSIconView icon) { this(context, icon, false); @@ -62,6 +64,11 @@ public class QSTileView extends QSTileBaseView { createLabel(); setOrientation(VERTICAL); setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP); + mColorLabelDefault = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary); + // The text color for unavailable tiles is textColorSecondary, same as secondaryLabel for + // contrast purposes + mColorLabelUnavailable = Utils.getColorAttr(getContext(), + android.R.attr.textColorSecondary); } TextView getLabel() { @@ -111,12 +118,8 @@ public class QSTileView extends QSTileBaseView { protected void handleStateChanged(QSTile.State state) { super.handleStateChanged(state); if (!Objects.equals(mLabel.getText(), state.label) || mState != state.state) { - if (state.state == Tile.STATE_UNAVAILABLE) { - int color = QSTileImpl.getColorForState(getContext(), state.state); - state.label = new SpannableStringBuilder().append(state.label, - new ForegroundColorSpan(color), - SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE); - } + mLabel.setTextColor(state.state == Tile.STATE_UNAVAILABLE ? mColorLabelUnavailable + : mColorLabelDefault); mState = state.state; mLabel.setText(state.label); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 00aef9aed85d..56dbe2b2cd99 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -498,7 +498,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mSysUiStateFlags = 0; mSysUiStateFlags |= ActivityManagerWrapper.getInstance().isScreenPinningActive() ? SYSUI_STATE_SCREEN_PINNING : 0; - mSysUiStateFlags |= (navBarFragment == null || !navBarFragment.isNavBarWindowVisible()) + mSysUiStateFlags |= (navBarFragment != null && !navBarFragment.isNavBarWindowVisible()) ? SYSUI_STATE_NAV_BAR_HIDDEN : 0; mSysUiStateFlags |= panelExpanded ? SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED : 0; @@ -608,6 +608,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mConnectionCallbacks.add(listener); listener.onConnectionChanged(mOverviewProxy != null); listener.onInteractionFlagsChanged(mInteractionFlags); + listener.onBackButtonAlphaChanged(mBackButtonAlpha, false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index c833ded6a85f..85848cafbfcb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -33,6 +33,7 @@ import android.view.View; import android.view.WindowManagerGlobal; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.systemui.Dependency; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.statusbar.CommandQueue.Callbacks; @@ -81,7 +82,7 @@ public class NavigationBarController implements Callbacks { @Override public void onDisplayReady(int displayId) { Display display = mDisplayManager.getDisplay(displayId); - createNavigationBar(display); + createNavigationBar(display, null); } // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to @@ -91,11 +92,12 @@ public class NavigationBarController implements Callbacks { * * @param includeDefaultDisplay {@code true} to create navigation bar on default display. */ - public void createNavigationBars(final boolean includeDefaultDisplay) { + public void createNavigationBars(final boolean includeDefaultDisplay, + RegisterStatusBarResult result) { Display[] displays = mDisplayManager.getDisplays(); for (Display display : displays) { if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) { - createNavigationBar(display); + createNavigationBar(display, result); } } } @@ -107,7 +109,7 @@ public class NavigationBarController implements Callbacks { * @param display the display to add navigation bar on. */ @VisibleForTesting - void createNavigationBar(Display display) { + void createNavigationBar(Display display, RegisterStatusBarResult result) { if (display == null) { return; } @@ -149,8 +151,14 @@ public class NavigationBarController implements Callbacks { ? Dependency.get(AutoHideController.class) : new AutoHideController(context, mHandler); navBar.setAutoHideController(autoHideController); - navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + navBar.restoreSystemUiVisibilityState(); mNavigationBars.append(displayId, navBar); + + if (result != null) { + navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken, + result.mImeWindowVis, result.mImeBackDisposition, + result.mShowImeSwitcher); + } }); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 2e35f0686d55..97f2dd0749f2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -22,7 +22,6 @@ import android.os.Trace; import android.util.Log; import android.view.View; import android.view.ViewGroup; -import android.view.ViewParent; import com.android.systemui.R; import com.android.systemui.bubbles.BubbleData; @@ -120,7 +119,7 @@ public class NotificationViewHierarchyManager { for (int i = 0; i < N; i++) { NotificationEntry ent = activeNotifications.get(i); if (ent.isRowDismissed() || ent.isRowRemoved() - || (mBubbleData.getBubble(ent.key) != null && !ent.showInShadeWhenBubble())) { + || (mBubbleData.hasBubbleWithKey(ent.key) && !ent.showInShadeWhenBubble())) { // we don't want to update removed notifications because they could // temporarily become children if they were isolated before. continue; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java index 99f5874448b5..b54de5a42ef8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java @@ -90,6 +90,8 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi @Override public void onPlaybackStateChanged(PlaybackState state) { if (state.getState() != PlaybackState.STATE_PLAYING) { + // Update the UI once, in case playback info changed while we were paused + mUpdatePlaybackUi.run(); clearTimer(); } else if (mSeekBarTimer == null) { startTimer(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java index 4ced702f479e..959342b27b56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -141,6 +141,11 @@ public class ButtonDispatcher { public void setVisibility(int visibility) { if (mVisibility == visibility) return; + if (mFadeAnimator != null) { + mFadeAnimator.cancel(); + mFadeAnimator = null; + } + mVisibility = visibility; final int N = mViews.size(); for (int i = 0; i < N; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 591b1b48ddc2..4d2b56c5e81a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -123,6 +123,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private static final boolean DEBUG = false; private static final String EXTRA_DISABLE_STATE = "disabled_state"; private static final String EXTRA_DISABLE2_STATE = "disabled2_state"; + private static final String EXTRA_SYSTEM_UI_VISIBILITY = "system_ui_visibility"; /** Allow some time inbetween the long press for back and recents. */ private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; @@ -156,7 +157,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private Locale mLocale; private int mLayoutDirection; - private int mSystemUiVisibility; + private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; private LightBarController mLightBarController; private AutoHideController mAutoHideController; @@ -277,6 +278,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (savedInstanceState != null) { mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0); mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0); + mSystemUiVisibility = savedInstanceState.getInt(EXTRA_SYSTEM_UI_VISIBILITY, 0); } mAccessibilityManagerWrapper.addCallback(mAccessibilityListener); @@ -316,6 +318,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (savedInstanceState != null) { mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState); } + mNavigationBarView.setNavigationIconHints(mNavigationIconHints); prepareNavigationBarView(); checkNavBarModes(); @@ -362,6 +365,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback super.onSaveInstanceState(outState); outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1); outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2); + outState.putInt(EXTRA_SYSTEM_UI_VISIBILITY, mSystemUiVisibility); if (mNavigationBarView != null) { mNavigationBarView.getLightTransitionsController().saveState(outState); } @@ -491,13 +495,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } } - /** - * Sets System UI flags to {@link NavigationBarFragment}. - * - * @see View#setSystemUiVisibility(int) - */ - public void setSystemUiVisibility(int systemUiVisibility) { - mSystemUiVisibility = systemUiVisibility; + /** Restores the System UI flags saved state to {@link NavigationBarFragment}. */ + public void restoreSystemUiVisibilityState() { final int barMode = computeBarMode(0, mSystemUiVisibility); if (barMode != -1) { mNavigationBarMode = barMode; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 0e9264b6b5a4..dd957b402b31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -1709,7 +1709,8 @@ public class NotificationPanelView extends PanelView implements min = Math.max(min, minHeight); } int maxHeight; - if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted) { + if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted + || mPulsing) { maxHeight = calculatePanelHeightQsExpanded(); } else { maxHeight = calculatePanelHeightShade(); 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 aaaf3edfba68..9fccf9132fc8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -660,7 +660,6 @@ public class StatusBar extends SystemUI implements DemoMode, mDisplayId = mDisplay.getDisplayId(); updateDisplaySize(); - Resources res = mContext.getResources(); mVibrateOnOpening = mContext.getResources().getBoolean( R.bool.config_vibrateOnIconAnimation); mVibratorHelper = Dependency.get(VibratorHelper.class); @@ -696,7 +695,7 @@ public class StatusBar extends SystemUI implements DemoMode, ex.rethrowFromSystemServer(); } - createAndAddWindows(); + createAndAddWindows(result); // Make sure we always have the most current wallpaper info. IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); @@ -778,7 +777,7 @@ public class StatusBar extends SystemUI implements DemoMode, // ================================================================================ // Constructing the view // ================================================================================ - protected void makeStatusBarView() { + protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) { final Context context = mContext; updateDisplaySize(); // populates mDisplayMetrics updateResources(); @@ -871,7 +870,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationLogger.setHeadsUpManager(mHeadsUpManager); putComponent(HeadsUpManager.class, mHeadsUpManager); - createNavigationBar(); + createNavigationBar(result); if (ENABLE_LOCKSCREEN_WALLPAPER) { mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler); @@ -1118,8 +1117,8 @@ public class StatusBar extends SystemUI implements DemoMode, // TODO(b/117478341): This was left such that CarStatusBar can override this method. // Try to remove this. - protected void createNavigationBar() { - mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */); + protected void createNavigationBar(@Nullable RegisterStatusBarResult result) { + mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */, result); } /** @@ -2401,12 +2400,8 @@ public class StatusBar extends SystemUI implements DemoMode, pw.println(BarTransitions.modeToString(transitions.getMode())); } - public void createAndAddWindows() { - addStatusBarWindow(); - } - - private void addStatusBarWindow() { - makeStatusBarView(); + public void createAndAddWindows(@Nullable RegisterStatusBarResult result) { + makeStatusBarView(result); mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight()); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index ffe3ece52e45..6bed43eb37b6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -288,7 +288,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true); mTestableLooper.processAllMessages(); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any()); + verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); verify(mFaceManager).isHardwareDetected(); verify(mFaceManager).hasEnrolledTemplates(anyInt()); } @@ -298,7 +298,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.dispatchStartedWakingUp(); mTestableLooper.processAllMessages(); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any()); + verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); } @Test @@ -317,7 +317,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.setKeyguardOccluded(true); mKeyguardUpdateMonitor.setAssistantVisible(true); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any()); + verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java index 26fa62b77d9a..4bb2395cc92d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java @@ -38,9 +38,9 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper -public final class StretchAnalogClockControllerTest extends SysuiTestCase { +public final class AnalogClockControllerTest extends SysuiTestCase { - private StretchAnalogClockController mClockController; + private AnalogClockController mClockController; @Mock SysuiColorExtractor mMockColorExtractor; @Before @@ -49,7 +49,7 @@ public final class StretchAnalogClockControllerTest extends SysuiTestCase { Resources res = getContext().getResources(); LayoutInflater layoutInflater = LayoutInflater.from(getContext()); - mClockController = new StretchAnalogClockController(res, layoutInflater, + mClockController = new AnalogClockController(res, layoutInflater, mMockColorExtractor); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 20f539bbebe5..40a53571ddf0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -146,7 +146,7 @@ public class BubbleControllerTest extends SysuiTestCase { when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData); when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel); - mBubbleData = new BubbleData(); + mBubbleData = new BubbleData(mContext); mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController, mBubbleData, mConfigurationController); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); @@ -177,25 +177,27 @@ public class BubbleControllerTest extends SysuiTestCase { public void testRemoveBubble() { mBubbleController.updateBubble(mRow.getEntry()); assertTrue(mBubbleController.hasBubbles()); - + verify(mNotificationEntryManager).updateNotifications(); verify(mBubbleStateChangeListener).onHasBubblesChanged(true); mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE); assertFalse(mStatusBarWindowController.getBubblesShowing()); assertTrue(mRow.getEntry().isBubbleDismissed()); - verify(mNotificationEntryManager).updateNotifications(); + verify(mNotificationEntryManager, times(2)).updateNotifications(); verify(mBubbleStateChangeListener).onHasBubblesChanged(false); } @Test public void testDismissStack() { mBubbleController.updateBubble(mRow.getEntry()); + verify(mNotificationEntryManager, times(1)).updateNotifications(); mBubbleController.updateBubble(mRow2.getEntry()); + verify(mNotificationEntryManager, times(2)).updateNotifications(); assertTrue(mBubbleController.hasBubbles()); mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); assertFalse(mStatusBarWindowController.getBubblesShowing()); - verify(mNotificationEntryManager).updateNotifications(); + verify(mNotificationEntryManager, times(3)).updateNotifications(); assertTrue(mRow.getEntry().isBubbleDismissed()); assertTrue(mRow2.getEntry().isBubbleDismissed()); } @@ -215,7 +217,7 @@ public class BubbleControllerTest extends SysuiTestCase { // Expand the stack BubbleStackView stackView = mBubbleController.getStackView(); - stackView.expandStack(); + mBubbleController.expandStack(); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); assertTrue(mStatusBarWindowController.getBubbleExpanded()); @@ -224,7 +226,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertFalse(mRow.getEntry().showInShadeWhenBubble()); // Collapse - stackView.collapseStack(); + mBubbleController.collapseStack(); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); assertFalse(mBubbleController.isStackExpanded()); assertFalse(mStatusBarWindowController.getBubbleExpanded()); @@ -245,23 +247,24 @@ public class BubbleControllerTest extends SysuiTestCase { // Expand BubbleStackView stackView = mBubbleController.getStackView(); - stackView.expandStack(); + mBubbleController.expandStack(); assertTrue(mBubbleController.isStackExpanded()); - verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key); - - // Last added is the one that is expanded - assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry()); - assertFalse(mRow2.getEntry().showInShadeWhenBubble()); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); - // Switch which bubble is expanded - stackView.setExpandedBubble(mRow.getEntry()); + // First added is the one that is expanded assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry()); assertFalse(mRow.getEntry().showInShadeWhenBubble()); + // Switch which bubble is expanded + mBubbleController.selectBubble(mRow2.getEntry().key); + stackView.setExpandedBubble(mRow2.getEntry()); + assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry()); + assertFalse(mRow2.getEntry().showInShadeWhenBubble()); + // collapse for previous bubble - verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key); + verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); // expand for selected bubble - verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key); // Collapse mBubbleController.collapseStack(); @@ -280,7 +283,7 @@ public class BubbleControllerTest extends SysuiTestCase { // Expand BubbleStackView stackView = mBubbleController.getStackView(); - stackView.expandStack(); + mBubbleController.expandStack(); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); @@ -299,30 +302,30 @@ public class BubbleControllerTest extends SysuiTestCase { // Expand BubbleStackView stackView = mBubbleController.getStackView(); - stackView.expandStack(); + mBubbleController.expandStack(); assertTrue(mBubbleController.isStackExpanded()); - verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); - // Last added is the one that is expanded - assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry()); - assertFalse(mRow2.getEntry().showInShadeWhenBubble()); + // First added is the one that is expanded + assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry()); + assertFalse(mRow.getEntry().showInShadeWhenBubble()); // Dismiss currently expanded mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(), BubbleController.DISMISS_USER_GESTURE); - verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key); + verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); // Make sure next bubble is selected - assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry()); - verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); + assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry()); + verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key); // Dismiss that one mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(), BubbleController.DISMISS_USER_GESTURE); // Make sure state changes and collapse happens - verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); + verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key); verify(mBubbleStateChangeListener).onHasBubblesChanged(false); assertFalse(mBubbleController.hasBubbles()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java index 801308fc77da..da31134d13b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java @@ -48,7 +48,7 @@ public class BubbleStackViewTest extends SysuiTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mStackView = new BubbleStackView(mContext, new BubbleData(), null); + mStackView = new BubbleStackView(mContext, new BubbleData(getContext()), null); mBubble.entry = mNotifEntry; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index 63d42a70aa98..c534de7e24a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.AlarmManager; import android.content.ContentResolver; @@ -102,6 +103,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void onBindSlice_readsMedia() { MediaMetadata metadata = mock(MediaMetadata.class); + when(metadata.getText(any())).thenReturn("metadata"); mProvider.onDozingChanged(true); mProvider.onMetadataChanged(metadata); mProvider.onBindSlice(mProvider.getUri()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java index 34a726d526a3..7d2ccdc8f0a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java @@ -96,21 +96,21 @@ public class NavigationBarControllerTest extends SysuiTestCase { @Test public void testCreateNavigationBarsIncludeDefaultTrue() { initializeDisplayManager(); - doNothing().when(mNavigationBarController).createNavigationBar(any()); + doNothing().when(mNavigationBarController).createNavigationBar(any(), any()); - mNavigationBarController.createNavigationBars(true); + mNavigationBarController.createNavigationBars(true, null); - verify(mNavigationBarController).createNavigationBar(any(Display.class)); + verify(mNavigationBarController).createNavigationBar(any(Display.class), any()); } @Test public void testCreateNavigationBarsIncludeDefaultFalse() { initializeDisplayManager(); - doNothing().when(mNavigationBarController).createNavigationBar(any()); + doNothing().when(mNavigationBarController).createNavigationBar(any(), any()); - mNavigationBarController.createNavigationBars(false); + mNavigationBarController.createNavigationBars(false, null); - verify(mNavigationBarController, never()).createNavigationBar(any()); + verify(mNavigationBarController, never()).createNavigationBar(any(), any()); } private void initializeDisplayManager() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 2172a125ba85..3662c3860177 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -98,7 +98,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mViewHierarchyManager = new NotificationViewHierarchyManager(mContext, mLockscreenUserManager, mGroupManager, mVisualStabilityManager, mock(StatusBarStateControllerImpl.class), mEntryManager, - () -> mShadeController, new BubbleData()); + () -> mShadeController, new BubbleData(mContext)); Dependency.get(InitController.class).executePostInitTasks(); mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer); } diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_clear.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_clear.xml deleted file mode 100644 index 59af0133bdf7..000000000000 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_clear.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:height="24dp" - android:viewportHeight="24" - android:viewportWidth="24" - android:width="24dp" > - <path - android:fillColor="#000000" - android:pathData="M9,20h6c1.66,0,3-1.34,3-3V6h0.5c0.41,0,0.75-0.34,0.75-0.75S18.91,4.5,18.5,4.5H18h-3l-1-1h-4l-1,1H6H5.5 c-0.41,0-0.75,0.34-0.75,0.75S5.09,6,5.5,6H6v11C6,18.66,7.34,20,9,20z M16.5,6v11c0,0.83-0.67,1.5-1.5,1.5H9 c-0.83,0-1.5-0.67-1.5-1.5V6H16.5z" /> - <path - android:fillColor="#000000" - android:pathData="M13.97,16c0.41,0,0.75-0.34,0.75-0.75v-6.5c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v6.5 C13.22,15.66,13.55,16,13.97,16z" /> - <path - android:fillColor="#000000" - android:pathData="M10,16c0.41,0,0.75-0.34,0.75-0.75v-6.5C10.75,8.34,10.41,8,10,8S9.25,8.34,9.25,8.75v6.5C9.25,15.66,9.59,16,10,16z" /> -</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_corp.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_corp.xml index b6f777749965..798907c386c7 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_corp.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_corp.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorHint" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M16,4c0-1.1-0.9-2-2-2h-4C8.9,2,8,2.9,8,4v2H2v12c0,1.66,1.34,3,3,3h14c1.66,0,3-1.34,3-3V6h-6V4z M9.5,4 c0-0.28,0.22-0.5,0.5-0.5h4c0.28,0,0.5,0.22,0.5,0.5v2h-5V4z M20.5,7.5V18c0,0.83-0.67,1.5-1.5,1.5H5c-0.83,0-1.5-0.67-1.5-1.5V7.5 H20.5z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_drag_handle.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_drag_handle.xml new file mode 100644 index 000000000000..a7ab99e39af6 --- /dev/null +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_drag_handle.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorHint"> + + <path + android:fillColor="@android:color/white" + android:pathData="M4.75,10.5h14.5c0.41,0,0.75-0.34,0.75-0.75S19.66,9,19.25,9H4.75C4.34,9,4,9.34,4,9.75S4.34,10.5,4.75,10.5z" /> + <path + android:fillColor="@android:color/white" + android:pathData="M4.75,15h14.5c0.41,0,0.75-0.34,0.75-0.75s-0.34-0.75-0.75-0.75H4.75C4.34,13.5,4,13.84,4,14.25S4.34,15,4.75,15z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_hourglass_top.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_hourglass_top.xml new file mode 100644 index 000000000000..8160e682f4f5 --- /dev/null +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_hourglass_top.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary"> + + <path + android:fillColor="@android:color/white" + android:pathData="M7,6.8c0,2.23,1.22,4.16,3.02,5.2C8.22,13.04,7,14.97,7,17.2V22h10v-4.8c0-2.23-1.22-4.16-3.02-5.2 +C15.78,10.96,17,9.03,17,6.8V2H7V6.8z +M15.5,17.2v3.3h-7v-3.3c0-1.6,0.87-3.1,2.26-3.9L12,12.59l1.24,0.71 +C14.63,14.1,15.5,15.6,15.5,17.2z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_info_no_shadow.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_info_no_shadow.xml index 7bd6028591e2..82924bb6c983 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_info_no_shadow.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_info_no_shadow.xml @@ -16,16 +16,16 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M11.99,2C6.47,2,2,6.48,2,12c0,5.52,4.47,10,9.99,10C17.52,22,22,17.52,22,12C22,6.48,17.52,2,11.99,2z M11.99,20.5 c-4.68,0-8.49-3.81-8.49-8.5c0-4.69,3.81-8.5,8.49-8.5c4.69,0,8.51,3.81,8.51,8.5C20.5,16.69,16.68,20.5,11.99,20.5z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,10.5c-0.41,0-0.75,0.34-0.75,0.75v5c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-5 C12.75,10.84,12.41,10.5,12,10.5z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 12 7 C 12.5522847498 7 13 7.44771525017 13 8 C 13 8.55228474983 12.5522847498 9 12 9 C 11.4477152502 9 11 8.55228474983 11 8 C 11 7.44771525017 11.4477152502 7 12 7 Z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_wallpaper.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_palette.xml index e58c7b8f1496..964955bc96ca 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_wallpaper.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_palette.xml @@ -16,7 +16,7 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <group @@ -26,20 +26,20 @@ android:translateX="2.000000" android:translateY="2.000000" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M-109-356.5c4.69,0,8.5,3.36,8.5,7.5c0,2.48-2.02,4.5-4.5,4.5h-1.77c-1.1,0-2,0.9-2,2 c0,0.45,0.16,0.89,0.46,1.27l0.02,0.02l0.02,0.02c0.17,0.2,0.27,0.44,0.27,0.68c0,0.55-0.45,1-1,1c-4.69,0-8.5-3.81-8.5-8.5 S-113.69-356.5-109-356.5 M-109-358c-5.51,0-10,4.49-10,10s4.49,10,10,10c1.38,0,2.5-1.12,2.5-2.5c0-0.61-0.23-1.2-0.64-1.67 c-0.08-0.1-0.13-0.21-0.13-0.33c0-0.28,0.22-0.5,0.5-0.5h1.77c3.31,0,6-2.69,6-6C-99-353.96-103.49-358-109-358L-109-358z" /> </group> </group> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 6.5 10 C 7.32842712475 10 8 10.6715728753 8 11.5 C 8 12.3284271247 7.32842712475 13 6.5 13 C 5.67157287525 13 5 12.3284271247 5 11.5 C 5 10.6715728753 5.67157287525 10 6.5 10 Z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 9.5 6 C 10.3284271247 6 11 6.67157287525 11 7.5 C 11 8.32842712475 10.3284271247 9 9.5 9 C 8.67157287525 9 8 8.32842712475 8 7.5 C 8 6.67157287525 8.67157287525 6 9.5 6 Z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 14.5 6 C 15.3284271247 6 16 6.67157287525 16 7.5 C 16 8.32842712475 15.3284271247 9 14.5 9 C 13.6715728753 9 13 8.32842712475 13 7.5 C 13 6.67157287525 13.6715728753 6 14.5 6 Z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 17.5 10 C 18.3284271247 10 19 10.6715728753 19 11.5 C 19 12.3284271247 18.3284271247 13 17.5 13 C 16.6715728753 13 16 12.3284271247 16 11.5 C 16 10.6715728753 16.6715728753 10 17.5 10 Z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_pin.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_pin.xml new file mode 100644 index 000000000000..35c0b810ec58 --- /dev/null +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_pin.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary"> + + <path + android:fillColor="@android:color/white" + android:pathData="M4.63,14.62C4.24,15.21,4.66,16,5.37,16h5.88c0,0,0,0,0,0v6.25c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75V16 +c0,0,0,0,0,0h5.84c0.71,0,1.13-0.79,0.74-1.38c-0.84-1.25-1.99-2.26-3.33-2.95V4.5h1.23c0.41,0,0.75-0.34,0.75-0.75 +S17.65,3,17.23,3H6.73C6.32,3,5.98,3.34,5.98,3.75S6.32,4.5,6.73,4.5H8v7.15C6.64,12.34,5.48,13.36,4.63,14.62z +M14.5,4.5v8.08 +L15.32,13c0.75,0.39,1.43,0.89,2,1.5H6.64c0.58-0.61,1.27-1.12,2.03-1.51l0.82-0.42V4.5H14.5z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_remove_no_shadow.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_remove_no_shadow.xml index 458223d84684..5fa740d63acc 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_remove_no_shadow.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_remove_no_shadow.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M3.97,20.03c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L12,13.06l6.97,6.97c0.15,0.15,0.34,0.22,0.53,0.22 s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06L13.06,12l6.97-6.97c0.29-0.29,0.29-0.77,0-1.06s-0.77-0.29-1.06,0L12,10.94 L5.03,3.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12l-6.97,6.97C3.68,19.26,3.68,19.74,3.97,20.03z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml index abb1b54ac88b..afa0a150bd65 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_setting.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,8.5c-1.93,0-3.5,1.57-3.5,3.5s1.57,3.5,3.5,3.5c1.93,0,3.5-1.57,3.5-3.5S13.93,8.5,12,8.5z M12,14c-1.1,0-2-0.9-2-2 s0.9-2,2-2c1.1,0,2,0.9,2,2S13.1,14,12,14z M21.29,13.9l-1.83-1.05c-0.3-0.17-0.49-0.49-0.48-0.84v-0.01 c0-0.35,0.18-0.67,0.48-0.84l1.83-1.05c0.48-0.28,0.64-0.89,0.37-1.37l-2-3.46c-0.19-0.32-0.52-0.5-0.87-0.5 c-0.17,0-0.34,0.04-0.5,0.13l-1.84,1.06c-0.14,0.08-0.29,0.12-0.45,0.12c-0.17,0-0.35-0.05-0.5-0.14c0,0-0.01,0-0.01-0.01 C15.2,5.77,15,5.47,15,5.12V3c0-0.55-0.45-1-1-1h-4C9.45,2,9,2.45,9,3v2.12c0,0.34-0.2,0.65-0.5,0.82c0,0-0.01,0-0.01,0.01 c-0.16,0.09-0.33,0.14-0.5,0.14c-0.15,0-0.31-0.04-0.45-0.12L5.71,4.9c-0.16-0.09-0.33-0.13-0.5-0.13c-0.35,0-0.68,0.18-0.87,0.5 l-2,3.46C2.06,9.21,2.23,9.82,2.71,10.1l1.83,1.05c0.3,0.17,0.49,0.49,0.48,0.84v0.01c0,0.35-0.18,0.67-0.48,0.84L2.71,13.9 c-0.48,0.28-0.64,0.89-0.37,1.37l2,3.46c0.19,0.32,0.52,0.5,0.87,0.5c0.17,0,0.34-0.04,0.5-0.13l1.84-1.06 c0.14-0.08,0.29-0.12,0.45-0.12c0.17,0,0.35,0.05,0.5,0.14c0,0,0.01,0,0.01,0.01C8.8,18.23,9,18.53,9,18.88V21c0,0.55,0.45,1,1,1h4 c0.55,0,1-0.45,1-1v-2.12c0-0.34,0.2-0.65,0.5-0.82c0,0,0.01,0,0.01-0.01c0.16-0.09,0.33-0.14,0.5-0.14c0.15,0,0.31,0.04,0.45,0.12 l1.84,1.06c0.16,0.09,0.33,0.13,0.5,0.13c0.35,0,0.68-0.18,0.87-0.5l2-3.46C21.94,14.79,21.77,14.18,21.29,13.9z M18.61,17.55 l-1.41-0.81c-0.36-0.21-0.78-0.32-1.2-0.32c-0.43,0-0.86,0.12-1.25,0.34c-0.77,0.44-1.25,1.25-1.25,2.12v1.62h-3v-1.62 c0-0.87-0.48-1.68-1.26-2.12c-0.38-0.22-0.81-0.33-1.25-0.33c-0.42,0-0.84,0.11-1.2,0.32l-1.41,0.81l-1.5-2.6l1.39-0.8 c0.76-0.44,1.24-1.26,1.23-2.15c0-0.88-0.47-1.7-1.23-2.14l-1.39-0.8l1.5-2.6L6.8,7.26c0.36,0.21,0.78,0.32,1.2,0.32 c0.43,0,0.86-0.12,1.25-0.34c0.77-0.44,1.25-1.25,1.25-2.12V3.5h3v1.62c0,0.87,0.48,1.68,1.26,2.12c0.38,0.22,0.81,0.33,1.25,0.33 c0.42,0,0.84-0.11,1.2-0.32l1.41-0.81l1.5,2.6l-1.39,0.8c-0.76,0.44-1.24,1.26-1.23,2.15c0,0.88,0.47,1.7,1.23,2.14l1.39,0.8 L18.61,17.55z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_smartspace_preferences.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_smartspace_preferences.xml index f588c16a24b1..b7d31a216cfd 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_smartspace_preferences.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_smartspace_preferences.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M15.08,8.01c-0.39-0.39-0.91-0.59-1.42-0.59c-0.51,0-1.02,0.2-1.41,0.59L0.59,19.67l3.75,3.75l11.66-11.66 c0.78-0.78,0.78-2.04,0.01-2.82L15.08,8.01z M4.34,21.29l-1.63-1.63l7.45-7.45l1.63,1.63L4.34,21.29z M14.93,10.7l-2.09,2.09 l-1.63-1.63l2.09-2.09c0.13-0.13,0.28-0.15,0.35-0.15c0.08,0,0.23,0.02,0.36,0.15l0.92,0.93C15.13,10.18,15.13,10.5,14.93,10.7z M17.67,5.25h1.08v1.08c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75V5.25h1.08c0.41,0,0.75-0.34,0.75-0.75 s-0.34-0.75-0.75-0.75h-1.08V2.67c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75v1.08h-1.08c-0.41,0-0.75,0.34-0.75,0.75 S17.26,5.25,17.67,5.25z M5.67,5.25h1.08v1.08c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75V5.25h1.08 c0.41,0,0.75-0.34,0.75-0.75S9.74,3.75,9.33,3.75H8.25V2.67c0-0.41-0.34-0.75-0.75-0.75S6.75,2.26,6.75,2.67v1.08H5.67 c-0.41,0-0.75,0.34-0.75,0.75S5.26,5.25,5.67,5.25z M21.33,15.75h-1.08v-1.08c0-0.41-0.34-0.75-0.75-0.75s-0.75,0.34-0.75,0.75 v1.08h-1.08c-0.41,0-0.75,0.34-0.75,0.75s0.34,0.75,0.75,0.75h1.08v1.08c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-1.08 h1.08c0.41,0,0.75-0.34,0.75-0.75S21.74,15.75,21.33,15.75z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_split_screen.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_split_screen.xml index 081f2d882329..649e555cdb92 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_split_screen.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_split_screen.xml @@ -16,13 +16,13 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M4,6v3c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6z M18.5,6v3c0,0.28-0.22,0.5-0.5,0.5H6 C5.72,9.5,5.5,9.28,5.5,9V6c0-0.28,0.22-0.5,0.5-0.5h12C18.28,5.5,18.5,5.72,18.5,6z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M4,18c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-3c0-1.1-0.9-2-2-2H6c-1.1,0-2,0.9-2,2V18z M5.5,15c0-0.28,0.22-0.5,0.5-0.5h12 c0.28,0,0.5,0.22,0.5,0.5v3c0,0.28-0.22,0.5-0.5,0.5H6c-0.28,0-0.5-0.22-0.5-0.5V15z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_warning.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_warning.xml index f9e742333493..e78ae9a2a522 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_warning.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_warning.xml @@ -16,16 +16,16 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M4.47,21h15.06c1.54,0,2.5-1.67,1.73-3L13.73,4.99c-0.39-0.67-1.06-1-1.73-1s-1.35,0.33-1.73,1L2.74,18 C1.97,19.33,2.93,21,4.47,21z M4.04,18.75l7.53-13.01c0.13-0.22,0.33-0.25,0.43-0.25s0.31,0.03,0.43,0.25l7.53,13.01 c0.13,0.22,0.05,0.41,0,0.5c-0.05,0.09-0.18,0.25-0.43,0.25H4.47c-0.25,0-0.38-0.16-0.43-0.25C3.98,19.16,3.91,18.97,4.04,18.75z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,14.75c0.41,0,0.75-0.34,0.75-0.75V9.75C12.75,9.33,12.41,9,12,9s-0.75,0.34-0.75,0.75V14 C11.25,14.41,11.59,14.75,12,14.75z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 12 16 C 12.5522847498 16 13 16.4477152502 13 17 C 13 17.5522847498 12.5522847498 18 12 18 C 11.4477152502 18 11 17.5522847498 11 17 C 11 16.4477152502 11.4477152502 16 12 16 Z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_widget.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_widget.xml index 60698183c7df..c3bc34976f0c 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_widget.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_widget.xml @@ -16,19 +16,19 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M11,5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v4c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2V5z M9.5,9c0,0.28-0.22,0.5-0.5,0.5H5 C4.72,9.5,4.5,9.28,4.5,9V5c0-0.28,0.22-0.5,0.5-0.5h4c0.28,0,0.5,0.22,0.5,0.5V9z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M9,13H5c-1.1,0-2,0.9-2,2v4c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2v-4C11,13.9,10.1,13,9,13z M9.5,19c0,0.28-0.22,0.5-0.5,0.5 H5c-0.28,0-0.5-0.22-0.5-0.5v-4c0-0.28,0.22-0.5,0.5-0.5h4c0.28,0,0.5,0.22,0.5,0.5V19z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M19,13h-4c-1.1,0-2,0.9-2,2v4c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2v-4C21,13.9,20.1,13,19,13z M19.5,19 c0,0.28-0.22,0.5-0.5,0.5h-4c-0.28,0-0.5-0.22-0.5-0.5v-4c0-0.28,0.22-0.5,0.5-0.5h4c0.28,0,0.5,0.22,0.5,0.5V19z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M18.41,2.76c-0.39-0.39-0.9-0.59-1.41-0.59s-1.02,0.2-1.41,0.59l-2.83,2.83c-0.78,0.78-0.78,2.05,0,2.83l2.83,2.83 c0.39,0.39,0.9,0.59,1.41,0.59s1.02-0.2,1.41-0.59l2.83-2.83c0.78-0.78,0.78-2.05,0-2.83L18.41,2.76z M20.18,7.35l-2.83,2.83 c-0.13,0.13-0.28,0.15-0.35,0.15s-0.23-0.02-0.35-0.15l-2.83-2.83C13.69,7.23,13.67,7.08,13.67,7s0.02-0.23,0.15-0.35l2.83-2.83 c0.13-0.13,0.28-0.15,0.35-0.15s0.23,0.02,0.35,0.15l2.83,2.83c0.13,0.13,0.15,0.28,0.15,0.35S20.31,7.23,20.18,7.35z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_clear.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_clear.xml deleted file mode 100644 index d04eb1f53c37..000000000000 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_clear.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:height="24dp" - android:viewportHeight="24" - android:viewportWidth="24" - android:width="24dp" > - <path - android:fillColor="#000000" - android:pathData="M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1 s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4z" /> - <path - android:fillColor="#000000" - android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z" /> -</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_corp.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_corp.xml index ed395433ae5b..76d8882097a7 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_corp.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_corp.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorHint" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M20,6h-4V4c0-1.11-0.89-2-2-2h-4C8.89,2,8,2.89,8,4v2H4C2.89,6,2.01,6.89,2.01,8L2,19c0,1.11,0.89,2,2,2h16 c1.11,0,2-0.89,2-2V8C22,6.89,21.11,6,20,6z M14,6h-4V4h4V6z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_drag_handle.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_drag_handle.xml new file mode 100644 index 000000000000..3117ae132fe8 --- /dev/null +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_drag_handle.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorHint"> + + <path + android:fillColor="@android:color/white" + android:pathData="M19,13H5c-0.55,0-1,0.45-1,1s0.45,1,1,1h14c0.55,0,1-0.45,1-1S19.55,13,19,13z" /> + <path + android:fillColor="@android:color/white" + android:pathData="M19,9H5c-0.55,0-1,0.45-1,1s0.45,1,1,1h14c0.55,0,1-0.45,1-1S19.55,9,19,9z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_hourglass_top.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_hourglass_top.xml new file mode 100644 index 000000000000..b389e4b83d29 --- /dev/null +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_hourglass_top.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary"> + + <path + android:fillColor="@android:color/white" + android:pathData="M17,2H7C6.45,2,6,2.45,6,3l0.01,3.75c0,0.79,0.32,1.55,0.87,2.11L10,12l-3.12,3.12c-0.56,0.56-0.87,1.32-0.88,2.11L6,21 +c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1v-3.77c0-0.8-0.32-1.56-0.88-2.12L14,12l3.12-3.13C17.68,8.31,18,7.54,18,6.75V3 +C18,2.45,17.55,2,17,2z +M15.71,16.21c0.19,0.19,0.29,0.44,0.29,0.71V20H8v-3.09c0-0.27,0.11-0.52,0.29-0.71L12,12.5L15.71,16.21z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_info_no_shadow.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_info_no_shadow.xml index dfa17d6142f4..f50fa2bcdba2 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_info_no_shadow.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_info_no_shadow.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2,2,6.48,2,12c0,5.52,4.48,10,10,10s10-4.48,10-10C22,6.48,17.52,2,12,2z M13,17c0,0.55-0.45,1-1,1s-1-0.45-1-1 v-5c0-0.55,0.45-1,1-1s1,0.45,1,1V17z M12,9.25c-0.69,0-1.25-0.56-1.25-1.25S11.31,6.75,12,6.75S13.25,7.31,13.25,8 S12.69,9.25,12,9.25z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_wallpaper.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_palette.xml index 880b2abc8752..e9a89ec569f2 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_wallpaper.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_palette.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,2C6.49,2,2,6.49,2,12s4.49,10,10,10c1.38,0,2.5-1.12,2.5-2.5c0-0.61-0.23-1.2-0.64-1.67c-0.08-0.1-0.13-0.21-0.13-0.33 c0-0.28,0.22-0.5,0.5-0.5H16c3.31,0,6-2.69,6-6C22,6.04,17.51,2,12,2z M6.5,13C5.67,13,5,12.33,5,11.5S5.67,10,6.5,10 S8,10.67,8,11.5S7.33,13,6.5,13z M9.5,9C8.67,9,8,8.33,8,7.5S8.67,6,9.5,6S11,6.67,11,7.5S10.33,9,9.5,9z M14.5,9 C13.67,9,13,8.33,13,7.5S13.67,6,14.5,6S16,6.67,16,7.5S15.33,9,14.5,9z M17.5,13c-0.83,0-1.5-0.67-1.5-1.5s0.67-1.5,1.5-1.5 s1.5,0.67,1.5,1.5S18.33,13,17.5,13z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_pin.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_pin.xml new file mode 100644 index 000000000000..698f718090fe --- /dev/null +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_pin.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary"> + + <path + android:fillColor="@android:color/white" + android:pathData="M5.71,14.29C5.08,14.92,5.52,16,6.41,16H11v6c0,0.55,0.45,1,1,1s1-0.45,1-1v-6h4.59c0.89,0,1.34-1.08,0.71-1.71L16,12V5 +h0.5c0.55,0,1-0.45,1-1s-0.45-1-1-1h-9c-0.55,0-1,0.45-1,1s0.45,1,1,1H8v7L5.71,14.29z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_remove_no_shadow.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_remove_no_shadow.xml index 22401a1a1cca..b3288d93d237 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_remove_no_shadow.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_remove_no_shadow.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M5.7,18.3c0.39,0.39,1.02,0.39,1.41,0L12,13.41l4.89,4.89c0.39,0.39,1.02,0.39,1.41,0s0.39-1.02,0-1.41L13.41,12l4.89-4.89 c0.38-0.38,0.38-1.02,0-1.4c-0.39-0.39-1.02-0.39-1.41,0c0,0,0,0,0,0L12,10.59L7.11,5.7c-0.39-0.39-1.02-0.39-1.41,0 s-0.39,1.02,0,1.41L10.59,12L5.7,16.89C5.31,17.28,5.31,17.91,5.7,18.3z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml index b4f0478f48b5..513633bdc57d 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M21.64,8.39l-1.6-2.76c-0.28-0.48-0.88-0.7-1.36-0.5l-2.14,0.91c-0.48-0.37-1.01-0.68-1.57-0.92l-0.27-2.2 C14.64,2.4,14.14,2,13.59,2h-3.18C9.86,2,9.36,2.4,9.3,2.92L9.04,5.11c-0.57,0.24-1.1,0.55-1.58,0.92L5.32,5.12 c-0.48-0.2-1.08,0.02-1.36,0.5l-1.6,2.76C2.08,8.86,2.18,9.48,2.6,9.8l1.94,1.45C4.51,11.49,4.5,11.74,4.5,12s0.01,0.51,0.04,0.76 L2.6,14.2c-0.42,0.31-0.52,0.94-0.24,1.41l1.6,2.76c0.28,0.48,0.88,0.7,1.36,0.5l2.14-0.91c0.48,0.37,1.01,0.68,1.57,0.92 l0.27,2.19C9.36,21.6,9.86,22,10.41,22h3.18c0.55,0,1.04-0.4,1.11-0.92l0.27-2.19c0.56-0.24,1.09-0.55,1.57-0.92l2.14,0.91 c0.48,0.2,1.08-0.02,1.36-0.5l1.6-2.76c0.28-0.48,0.18-1.1-0.24-1.42l-1.94-1.45c0.03-0.25,0.04-0.5,0.04-0.76 s-0.01-0.51-0.04-0.76L21.4,9.8C21.82,9.49,21.92,8.86,21.64,8.39z M12,15.5c-1.93,0-3.5-1.57-3.5-3.5s1.57-3.5,3.5-3.5 s3.5,1.57,3.5,3.5S13.93,15.5,12,15.5z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_smartspace_preferences.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_smartspace_preferences.xml index 57ae91f89839..4ca296701e6f 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_smartspace_preferences.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_smartspace_preferences.xml @@ -16,16 +16,16 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M21.23,2.43L19.5,3.4l-1.73-0.97c-0.22-0.12-0.46,0.12-0.34,0.34L18.4,4.5l-0.97,1.73c-0.12,0.22,0.12,0.46,0.34,0.34 L19.5,5.6l1.73,0.97c0.22,0.12,0.46-0.12,0.34-0.34L20.6,4.5l0.97-1.73C21.69,2.55,21.45,2.31,21.23,2.43z M14.37,7.29 c-0.39-0.39-1.02-0.39-1.41,0L1.29,18.96c-0.39,0.39-0.39,1.02,0,1.41l2.34,2.34c0.39,0.39,1.02,0.39,1.41,0L16.7,11.05 c0.39-0.39,0.39-1.02,0-1.41L14.37,7.29z M13.34,12.78l-2.12-2.12l2.44-2.44l2.12,2.12L13.34,12.78z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M21.23,14.43L19.5,15.4l-1.73-0.97c-0.22-0.12-0.46,0.12-0.34,0.34l0.97,1.73l-0.97,1.73c-0.12,0.22,0.12,0.46,0.34,0.34 l1.73-0.97l1.73,0.97c0.22,0.12,0.46-0.12,0.34-0.34L20.6,16.5l0.97-1.73C21.69,14.55,21.45,14.31,21.23,14.43z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M9.23,2.43L7.5,3.4L5.77,2.43C5.55,2.31,5.31,2.55,5.43,2.77L6.4,4.5L5.43,6.23C5.31,6.45,5.55,6.69,5.77,6.57L7.5,5.6 l1.73,0.97c0.22,0.12,0.46-0.12,0.34-0.34L8.6,4.5l0.97-1.73C9.69,2.55,9.45,2.31,9.23,2.43z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_split_screen.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_split_screen.xml index dc3bd95eb624..6eddf3d86864 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_split_screen.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_split_screen.xml @@ -16,13 +16,13 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M18,2H6C4.9,2,4,2.9,4,4v5c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M18,13H6c-1.1,0-2,0.9-2,2v5c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-5C20,13.9,19.1,13,18,13z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_warning.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_warning.xml index 184714c8e4d3..41987590a702 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_warning.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_warning.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12.87,3.49c-0.39-0.67-1.35-0.67-1.73,0l-9.27,16C1.48,20.17,1.96,21,2.73,21h18.53c0.77,0,1.25-0.83,0.87-1.5L12.87,3.49 z M11,10c0-0.55,0.45-1,1-1s1,0.45,1,1v3c0,0.55-0.45,1-1,1s-1-0.45-1-1V10z M12,18.25c-0.69,0-1.25-0.56-1.25-1.25 s0.56-1.25,1.25-1.25s1.25,0.56,1.25,1.25S12.69,18.25,12,18.25z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_widget.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_widget.xml index ca09fc9e4caf..7316c02d5214 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_widget.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_widget.xml @@ -16,19 +16,19 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M17.7,2.3c-0.4-0.4-1-0.4-1.4,0l-4,4c-0.4,0.4-0.4,1,0,1.4l4,4c0.4,0.4,1,0.4,1.4,0l4-4c0.4-0.4,0.4-1,0-1.4L17.7,2.3z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M11,4c0-0.5-0.4-1-1-1H4C3.5,3,3,3.5,3,4v6c0,0.6,0.5,1,1,1h6c0.6,0,1-0.4,1-1V4z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M20,21c0.5,0,1-0.5,1-1v-6c0-0.6-0.5-1-1-1h-6c-0.6,0-1,0.4-1,1v6c0,0.5,0.4,1,1,1H20z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M10,13H4c-0.5,0-1,0.4-1,1v6c0,0.5,0.5,1,1,1h6c0.6,0,1-0.5,1-1v-6C11,13.4,10.6,13,10,13z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_clear.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_clear.xml deleted file mode 100644 index 49e7f1de3755..000000000000 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_clear.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:height="24dp" - android:viewportHeight="24" - android:viewportWidth="24" - android:width="24dp" > - <path - android:fillColor="#000000" - android:pathData="M20,4h-1h-4c0-0.55-0.45-1-1-1h-4C9.45,3,9,3.45,9,4H5H4C3.59,4,3.25,4.34,3.25,4.75S3.59,5.5,4,5.5h1V18 c0,1.66,1.34,3,3,3h8c1.66,0,3-1.34,3-3V5.5h1c0.41,0,0.75-0.34,0.75-0.75S20.41,4,20,4z M17.5,18c0,0.83-0.67,1.5-1.5,1.5H8 c-0.83,0-1.5-0.67-1.5-1.5V5.5h11V18z" /> - <path - android:fillColor="#000000" - android:pathData="M14.25,8c-0.41,0-0.75,0.34-0.75,0.75v7.5c0,0.41,0.34,0.75,0.75,0.75S15,16.66,15,16.25v-7.5C15,8.34,14.66,8,14.25,8z" /> - <path - android:fillColor="#000000" - android:pathData="M9.75,8C9.34,8,9,8.34,9,8.75v7.5C9,16.66,9.34,17,9.75,17s0.75-0.34,0.75-0.75v-7.5C10.5,8.34,10.16,8,9.75,8z" /> -</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_corp.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_corp.xml index f7b7f779e32d..dccc23c82530 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_corp.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_corp.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorHint" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M20,6h-4V4c0-1.1-0.9-2-2-2h-4C8.9,2,8,2.9,8,4v2H4C2.9,6,2,6.9,2,8v11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8 C22,6.9,21.1,6,20,6z M9.5,4c0-0.28,0.22-0.5,0.5-0.5h4c0.28,0,0.5,0.22,0.5,0.5v2h-5V4z M20.5,19c0,0.28-0.22,0.5-0.5,0.5H4 c-0.28,0-0.5-0.22-0.5-0.5V8c0-0.28,0.22-0.5,0.5-0.5h16c0.28,0,0.5,0.22,0.5,0.5V19z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_drag_handle.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_drag_handle.xml new file mode 100644 index 000000000000..68c0a8022e79 --- /dev/null +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_drag_handle.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorHint"> + + <path + android:fillColor="@android:color/white" + android:pathData="M5.75,10.5h12.5c0.41,0,0.75-0.34,0.75-0.75S18.66,9,18.25,9H5.75C5.34,9,5,9.34,5,9.75S5.34,10.5,5.75,10.5z" /> + <path + android:fillColor="@android:color/white" + android:pathData="M18.25,13.5H5.75C5.34,13.5,5,13.84,5,14.25S5.34,15,5.75,15h12.5c0.41,0,0.75-0.34,0.75-0.75S18.66,13.5,18.25,13.5z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_hourglass_top.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_hourglass_top.xml new file mode 100644 index 000000000000..0fd3229c26f3 --- /dev/null +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_hourglass_top.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary"> + + <path + android:fillColor="@android:color/white" + android:pathData="M16,3H8C7.45,3,7,3.45,7,4v1.93v0c0,0.33,0.03,0.66,0.1,0.98c0.19,0.96,0.66,1.85,1.37,2.56L11,12l-2.54,2.54 +C7.53,15.47,7,16.74,7,18.07V20c0,0.55,0.45,1,1,1h8c0.55,0,1-0.45,1-1v-1.93c0-1.33-0.53-2.6-1.46-3.54L13,12l2.54-2.54 +c0.7-0.7,1.18-1.59,1.37-2.56C16.97,6.59,17,6.26,17,5.93v0V4C17,3.45,16.55,3,16,3z +M14.47,15.6c0.66,0.66,1.03,1.54,1.03,2.47 +v1.43h-7v-1.43c0-0.93,0.36-1.81,1.03-2.47L12,13.12L14.47,15.6z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_info_no_shadow.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_info_no_shadow.xml index 6c9c732af347..f799d40cacc7 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_info_no_shadow.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_info_no_shadow.xml @@ -16,16 +16,16 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M4.92,4.94c-3.9,3.91-3.9,10.24,0.01,14.14s10.24,3.9,14.14-0.01C20.95,17.2,22,14.65,22,12c0-2.65-1.06-5.19-2.93-7.07 C15.16,1.03,8.83,1.03,4.92,4.94z M18,18c-1.6,1.59-3.76,2.48-6.02,2.48c-4.69-0.01-8.49-3.83-8.48-8.52 c0.01-4.69,3.83-8.49,8.52-8.48c4.69,0.01,8.49,3.83,8.48,8.52C20.49,14.25,19.6,16.41,18,18z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 12 7 C 12.5522847498 7 13 7.44771525017 13 8 C 13 8.55228474983 12.5522847498 9 12 9 C 11.4477152502 9 11 8.55228474983 11 8 C 11 7.44771525017 11.4477152502 7 12 7 Z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,10.5c-0.41,0-0.75,0.34-0.75,0.75v5c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75v-5 C12.75,10.84,12.41,10.5,12,10.5z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_wallpaper.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_palette.xml index e58c7b8f1496..964955bc96ca 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_wallpaper.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_palette.xml @@ -16,7 +16,7 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <group @@ -26,20 +26,20 @@ android:translateX="2.000000" android:translateY="2.000000" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M-109-356.5c4.69,0,8.5,3.36,8.5,7.5c0,2.48-2.02,4.5-4.5,4.5h-1.77c-1.1,0-2,0.9-2,2 c0,0.45,0.16,0.89,0.46,1.27l0.02,0.02l0.02,0.02c0.17,0.2,0.27,0.44,0.27,0.68c0,0.55-0.45,1-1,1c-4.69,0-8.5-3.81-8.5-8.5 S-113.69-356.5-109-356.5 M-109-358c-5.51,0-10,4.49-10,10s4.49,10,10,10c1.38,0,2.5-1.12,2.5-2.5c0-0.61-0.23-1.2-0.64-1.67 c-0.08-0.1-0.13-0.21-0.13-0.33c0-0.28,0.22-0.5,0.5-0.5h1.77c3.31,0,6-2.69,6-6C-99-353.96-103.49-358-109-358L-109-358z" /> </group> </group> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 6.5 10 C 7.32842712475 10 8 10.6715728753 8 11.5 C 8 12.3284271247 7.32842712475 13 6.5 13 C 5.67157287525 13 5 12.3284271247 5 11.5 C 5 10.6715728753 5.67157287525 10 6.5 10 Z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 9.5 6 C 10.3284271247 6 11 6.67157287525 11 7.5 C 11 8.32842712475 10.3284271247 9 9.5 9 C 8.67157287525 9 8 8.32842712475 8 7.5 C 8 6.67157287525 8.67157287525 6 9.5 6 Z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 14.5 6 C 15.3284271247 6 16 6.67157287525 16 7.5 C 16 8.32842712475 15.3284271247 9 14.5 9 C 13.6715728753 9 13 8.32842712475 13 7.5 C 13 6.67157287525 13.6715728753 6 14.5 6 Z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 17.5 10 C 18.3284271247 10 19 10.6715728753 19 11.5 C 19 12.3284271247 18.3284271247 13 17.5 13 C 16.6715728753 13 16 12.3284271247 16 11.5 C 16 10.6715728753 16.6715728753 10 17.5 10 Z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_pin.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_pin.xml new file mode 100644 index 000000000000..f1bf5c345474 --- /dev/null +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_pin.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary"> + + <path + android:fillColor="@android:color/white" + android:pathData="M5.71,14.29C5.08,14.92,5.53,16,6.42,16h4.83v6.25c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75V16h4.84 +c0.89,0,1.34-1.08,0.71-1.71L16,12V4.5h1.23c0.41,0,0.75-0.34,0.75-0.75S17.65,3,17.23,3H16H8H6.73C6.32,3,5.98,3.34,5.98,3.75 +S6.32,4.5,6.73,4.5H8V12L5.71,14.29z +M14.5,4.5V12c0,0.4,0.16,0.78,0.44,1.06l1.44,1.44H7.62l1.44-1.44C9.34,12.78,9.5,12.4,9.5,12 +V4.5H14.5z" /> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_remove_no_shadow.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_remove_no_shadow.xml index 82c2a3197e00..864a047844a4 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_remove_no_shadow.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_remove_no_shadow.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M5.22,18.78C5.37,18.93,5.56,19,5.75,19s0.38-0.07,0.53-0.22L12,13.06l5.72,5.72c0.15,0.15,0.34,0.22,0.53,0.22 s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06L13.06,12l5.72-5.72c0.29-0.29,0.29-0.77,0-1.06s-0.77-0.29-1.06,0L12,10.94 L6.28,5.22c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12l-5.72,5.72C4.93,18.01,4.93,18.49,5.22,18.78z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml index c4c5eaab72f5..6ff3144b9a73 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml @@ -16,13 +16,13 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M2.43,15.45l1.79,3.09c0.25,0.45,0.74,0.73,1.25,0.73c0.17,0,0.35-0.03,0.52-0.09l1.76-0.7c0.25,0.17,0.51,0.31,0.77,0.45 l0.26,1.84c0.09,0.71,0.69,1.24,1.42,1.24h3.61c0.72,0,1.33-0.53,1.43-1.19l0.26-1.86c0.25-0.14,0.51-0.28,0.76-0.45l1.76,0.7 c0.17,0.07,0.35,0.1,0.53,0.1c0.5,0,0.98-0.27,1.23-0.72l1.82-3.14c0.34-0.61,0.19-1.38-0.36-1.82l-1.48-1.16 c0.01-0.15,0.02-0.29,0.02-0.45s-0.01-0.3-0.02-0.45l1.48-1.16c0.55-0.43,0.7-1.19,0.35-1.84l-1.8-3.1 c-0.25-0.45-0.74-0.73-1.26-0.73c-0.17,0-0.35,0.03-0.52,0.09l-1.76,0.7c-0.25-0.17-0.51-0.31-0.77-0.45l-0.26-1.84 c-0.09-0.71-0.69-1.24-1.42-1.24h-3.61c-0.71,0-1.32,0.54-1.41,1.22L8.52,5.09C8.26,5.23,8.01,5.37,7.75,5.54L5.99,4.83 c-0.17-0.07-0.35-0.1-0.52-0.1c-0.5,0-0.98,0.27-1.22,0.72L2.43,8.55c-0.36,0.61-0.21,1.4,0.36,1.84l1.48,1.16 C4.27,11.7,4.26,11.85,4.26,12c0,0.16,0.01,0.3,0.02,0.45l-1.49,1.16C2.24,14.04,2.09,14.8,2.43,15.45z M5.2,13.63l0.63-0.49 l-0.05-0.79c-0.01-0.11-0.01-0.58,0-0.7l0.05-0.79L5.2,10.37L3.77,9.25l1.74-3l1.69,0.68l0.73,0.29l0.66-0.43 c0.19-0.13,0.4-0.25,0.65-0.38l0.67-0.36L10,5.3l0.25-1.79h3.48l0.26,1.8l0.11,0.76l0.69,0.36c0.23,0.12,0.44,0.24,0.64,0.37 l0.65,0.43l0.72-0.29l1.7-0.68l1.75,3.02l-1.43,1.12l-0.62,0.49l0.05,0.79c0.01,0.11,0.01,0.58,0,0.7l-0.05,0.79l0.62,0.49 l1.43,1.12l-1.74,3.02l-1.69-0.68l-0.72-0.29l-0.65,0.43c-0.19,0.13-0.4,0.25-0.65,0.38l-0.67,0.36l-0.11,0.75l-0.25,1.77h-3.5 L10,18.71l-0.11-0.76l-0.69-0.36c-0.23-0.12-0.44-0.24-0.64-0.37l-0.65-0.43l-0.72,0.29L5.5,17.76l-1.73-3.01L5.2,13.63z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,16c2.21,0,4-1.79,4-4s-1.79-4-4-4c-2.21,0-4,1.79-4,4S9.79,16,12,16z M12,9.5c1.38,0,2.5,1.12,2.5,2.5 s-1.12,2.5-2.5,2.5c-1.38,0-2.5-1.12-2.5-2.5S10.62,9.5,12,9.5z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_smartspace_preferences.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_smartspace_preferences.xml index 790248ade6ee..3cc9e51c21cb 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_smartspace_preferences.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_smartspace_preferences.xml @@ -16,10 +16,10 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M14.38,7.3C14.18,7.1,13.92,7,13.66,7c-0.26,0-0.51,0.1-0.71,0.29L1.29,18.96c-0.39,0.39-0.39,1.02,0,1.41l2.34,2.34 C3.82,22.9,4.08,23,4.34,23s0.51-0.1,0.71-0.29L16.7,11.05c0.39-0.39,0.39-1.02,0-1.41L14.38,7.3z M4.34,21.29l-1.63-1.63 l7.45-7.45l1.63,1.63L4.34,21.29z M12.84,12.78l-1.63-1.63l2.45-2.45l1.62,1.64L12.84,12.78z M17.75,5.25h1v1 C18.75,6.66,19.09,7,19.5,7s0.75-0.34,0.75-0.75v-1h1C21.66,5.25,22,4.91,22,4.5s-0.34-0.75-0.75-0.75h-1v-1 C20.25,2.34,19.91,2,19.5,2s-0.75,0.34-0.75,0.75v1h-1C17.34,3.75,17,4.09,17,4.5S17.34,5.25,17.75,5.25z M5.75,5.25h1v1 C6.75,6.66,7.09,7,7.5,7s0.75-0.34,0.75-0.75v-1h1C9.66,5.25,10,4.91,10,4.5S9.66,3.75,9.25,3.75h-1v-1C8.25,2.34,7.91,2,7.5,2 S6.75,2.34,6.75,2.75v1h-1C5.34,3.75,5,4.09,5,4.5S5.34,5.25,5.75,5.25z M21.25,15.75h-1v-1c0-0.41-0.34-0.75-0.75-0.75 s-0.75,0.34-0.75,0.75v1h-1c-0.41,0-0.75,0.34-0.75,0.75s0.34,0.75,0.75,0.75h1v1c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75 v-1h1c0.41,0,0.75-0.34,0.75-0.75S21.66,15.75,21.25,15.75z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_split_screen.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_split_screen.xml index 013b40f41cff..aaf490046407 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_split_screen.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_split_screen.xml @@ -16,13 +16,13 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M5,11h14c0.55,0,1-0.45,1-1V4c0-0.55-0.45-1-1-1H5C4.45,3,4,3.45,4,4v6C4,10.55,4.45,11,5,11z M5.5,4.5h13v5h-13V4.5z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M4,20c0,0.55,0.45,1,1,1h14c0.55,0,1-0.45,1-1v-6c0-0.55-0.45-1-1-1H5c-0.55,0-1,0.45-1,1V20z M5.5,14.5h13v5h-13V14.5z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_warning.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_warning.xml index 4af8a3734d1d..63d7b78f76c2 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_warning.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_warning.xml @@ -16,16 +16,16 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M4.47,21h15.06c1.54,0,2.5-1.67,1.73-3L13.73,4.99c-0.39-0.67-1.06-1-1.73-1s-1.35,0.33-1.73,1L2.74,18 C1.97,19.33,2.93,21,4.47,21z M4.04,18.75l7.53-13.01c0.13-0.22,0.33-0.25,0.43-0.25s0.31,0.03,0.43,0.25l7.53,13.01 c0.13,0.22,0.05,0.41,0,0.5c-0.05,0.09-0.18,0.25-0.43,0.25H4.47c-0.25,0-0.38-0.16-0.43-0.25C3.98,19.16,3.91,18.97,4.04,18.75z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M12,14.5c0.41,0,0.75-0.34,0.75-0.75v-4C12.75,9.33,12.41,9,12,9s-0.75,0.34-0.75,0.75v4C11.25,14.16,11.59,14.5,12,14.5z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M 12 16 C 12.5522847498 16 13 16.4477152502 13 17 C 13 17.5522847498 12.5522847498 18 12 18 C 11.4477152502 18 11 17.5522847498 11 17 C 11 16.4477152502 11.4477152502 16 12 16 Z" /> </vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_widget.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_widget.xml index 7cbf7f1ff0e7..df3a9fdcc40f 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_widget.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_widget.xml @@ -16,19 +16,19 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" - android:viewportHeight="24" + android:viewportHeight="24" android:tint="?android:attr/textColorPrimary" android:viewportWidth="24" android:width="24dp" > <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M10,3H4C3.45,3,3,3.45,3,4v6c0,0.55,0.45,1,1,1h6c0.55,0,1-0.45,1-1V4C11,3.45,10.55,3,10,3z M9.5,9.5h-5v-5h5V9.5z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M10,13H4c-0.55,0-1,0.45-1,1v6c0,0.55,0.45,1,1,1h6c0.55,0,1-0.45,1-1v-6C11,13.45,10.55,13,10,13z M9.5,19.5h-5v-5h5 V19.5z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M20,13h-6c-0.55,0-1,0.45-1,1v6c0,0.55,0.45,1,1,1h6c0.55,0,1-0.45,1-1v-6C21,13.45,20.55,13,20,13z M19.5,19.5h-5v-5h5 V19.5z" /> <path - android:fillColor="#000000" + android:fillColor="@android:color/white" android:pathData="M21.95,6.29l-4.24-4.24c-0.2-0.2-0.45-0.29-0.71-0.29s-0.51,0.1-0.71,0.29l-4.24,4.24c-0.39,0.39-0.39,1.02,0,1.41 l4.24,4.24c0.2,0.2,0.45,0.29,0.71,0.29s0.51-0.1,0.71-0.29l4.24-4.24C22.34,7.32,22.34,6.68,21.95,6.29z M17,10.54L13.46,7 L17,3.46L20.54,7L17,10.54z" /> </vector>
\ No newline at end of file diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java index 46e3226bb751..7b6a12822faa 100644 --- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java +++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java @@ -111,6 +111,15 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + // MotionEventInjector would cancel any injected gesture when any MotionEvent arrives. + // For user using an external device to control the pointer movement, it's almost + // impossible to perform the gestures. Any slightly unintended movement results in the + // cancellation of the gesture. + if ((event.isFromSource(InputDevice.SOURCE_MOUSE) + && event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) + && mOpenGesturesInProgress.get(EVENT_SOURCE, false)) { + return; + } cancelAnyPendingInjectedEvents(); sendMotionEventToNext(event, rawEvent, policyFlags); } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index fdc3567aa002..a94d1dc7f243 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -806,6 +806,17 @@ public final class AutofillManagerService mAugmentedAutofillState.injectAugmentedAutofillInfo(options, userId, packageName); return options; } + + @Override + public boolean isAugmentedAutofillServiceForUser(int callingUid, int userId) { + synchronized (mLock) { + final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); + if (service != null) { + return service.isAugmentedAutofillServiceForUserLocked(callingUid); + } + } + return false; + } } /** diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 4bd6fbd39de4..f1963b37a6cf 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -1165,6 +1165,11 @@ final class AutofillManagerServiceImpl return true; } + boolean isAugmentedAutofillServiceForUserLocked(int callingUid) { + return mRemoteAugmentedAutofillServiceInfo != null + && mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid == callingUid; + } + /** * Sets which packages and activities can trigger augmented autofill. * diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 757c2dc7f6f1..7f411d83b34b 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -60,8 +60,8 @@ import android.util.SparseBooleanArray; import android.view.contentcapture.ContentCaptureCondition; import android.view.contentcapture.ContentCaptureHelper; import android.view.contentcapture.ContentCaptureManager; +import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.IContentCaptureManager; -import android.view.contentcapture.UserDataRemovalRequest; import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.AbstractRemoteService; @@ -583,14 +583,14 @@ public final class ContentCaptureManagerService extends } @Override - public void removeUserData(@NonNull UserDataRemovalRequest request) { + public void removeData(@NonNull DataRemovalRequest request) { Preconditions.checkNotNull(request); assertCalledByPackageOwner(request.getPackageName()); final int userId = UserHandle.getCallingUserId(); synchronized (mLock) { final ContentCapturePerUserService service = getServiceForUserLocked(userId); - service.removeUserDataLocked(request); + service.removeDataLocked(request); } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 564952697250..b4a1f381f7ff 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -57,7 +57,7 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.view.contentcapture.ContentCaptureCondition; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.WhitelistHelper; @@ -343,12 +343,12 @@ final class ContentCapturePerUserService } @GuardedBy("mLock") - public void removeUserDataLocked(@NonNull UserDataRemovalRequest request) { + public void removeDataLocked(@NonNull DataRemovalRequest request) { if (!isEnabledLocked()) { return; } assertCallerLocked(request.getPackageName()); - mRemoteService.onUserDataRemovalRequest(request); + mRemoteService.onDataRemovalRequest(request); } @GuardedBy("mLock") diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java index 3fa3fdf6d36e..2171033c5a28 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java @@ -29,7 +29,7 @@ import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.SnapshotData; import android.util.Slog; import android.view.contentcapture.ContentCaptureContext; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.internal.os.IResultReceiver; @@ -120,10 +120,10 @@ final class RemoteContentCaptureService } /** - * Called by {@link ContentCaptureServerSession} to request removal of user data. + * Called by {@link ContentCaptureServerSession} to request removal of content capture data. */ - public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) { - scheduleAsyncRequest((s) -> s.onUserDataRemovalRequest(request)); + public void onDataRemovalRequest(@NonNull DataRemovalRequest request) { + scheduleAsyncRequest((s) -> s.onDataRemovalRequest(request)); } /** diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java index 6018f008054c..5c5b477352b1 100644 --- a/services/core/java/com/android/server/BluetoothService.java +++ b/services/core/java/com/android/server/BluetoothService.java @@ -18,11 +18,10 @@ package com.android.server; import android.bluetooth.BluetoothAdapter; import android.content.Context; -import android.os.SystemProperties; -class BluetoothService extends SystemService { - private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless"; +import com.android.internal.os.RoSystemProperties; +class BluetoothService extends SystemService { private BluetoothManagerService mBluetoothManagerService; private boolean mInitialized = false; @@ -48,7 +47,7 @@ class BluetoothService extends SystemService { publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService); } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY && - !SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false)) { + !RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER) { initialize(); } } diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 833faa6f3faf..52a4218238e7 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -1399,8 +1399,8 @@ public class DeviceIdleController extends SystemService } break; case MSG_TEMP_APP_WHITELIST_TIMEOUT: { // TODO: What is keeping the device awake at this point? Does it need to be? - int uid = msg.arg1; - checkTempAppWhitelistTimeout(uid); + int appId = msg.arg1; + checkTempAppWhitelistTimeout(appId); } break; case MSG_REPORT_MAINTENANCE_ACTIVITY: { // TODO: What is keeping the device awake at this point? Does it need to be? @@ -1656,9 +1656,9 @@ public class DeviceIdleController extends SystemService } // duration in milliseconds - public void addPowerSaveTempWhitelistAppDirect(int appId, long duration, boolean sync, + public void addPowerSaveTempWhitelistAppDirect(int uid, long duration, boolean sync, String reason) { - addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration, sync, reason); + addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, sync, reason); } // duration in milliseconds @@ -2357,8 +2357,7 @@ public class DeviceIdleController extends SystemService long duration, int userId, boolean sync, String reason) { try { int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId); - int appId = UserHandle.getAppId(uid); - addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason); + addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration, sync, reason); } catch (NameNotFoundException e) { } } @@ -2367,10 +2366,11 @@ public class DeviceIdleController extends SystemService * Adds an app to the temporary whitelist and resets the endTime for granting the * app an exemption to access network and acquire wakelocks. */ - void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int appId, + void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int uid, long duration, boolean sync, String reason) { final long timeNow = SystemClock.elapsedRealtime(); boolean informWhitelistChanged = false; + int appId = UserHandle.getAppId(uid); synchronized (this) { int callingAppId = UserHandle.getAppId(callingUid); if (callingAppId >= Process.FIRST_APPLICATION_UID) { @@ -2395,7 +2395,7 @@ public class DeviceIdleController extends SystemService // No pending timeout for the app id, post a delayed message try { mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_START, - reason, appId); + reason, uid); } catch (RemoteException e) { } postTempActiveTimeoutMessage(appId, duration); @@ -2440,34 +2440,34 @@ public class DeviceIdleController extends SystemService } } - private void postTempActiveTimeoutMessage(int uid, long delay) { + private void postTempActiveTimeoutMessage(int appId, long delay) { if (DEBUG) { - Slog.d(TAG, "postTempActiveTimeoutMessage: uid=" + uid + ", delay=" + delay); + Slog.d(TAG, "postTempActiveTimeoutMessage: appId=" + appId + ", delay=" + delay); } - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0), - delay); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, appId, 0), delay); } - void checkTempAppWhitelistTimeout(int uid) { + void checkTempAppWhitelistTimeout(int appId) { final long timeNow = SystemClock.elapsedRealtime(); if (DEBUG) { - Slog.d(TAG, "checkTempAppWhitelistTimeout: uid=" + uid + ", timeNow=" + timeNow); + Slog.d(TAG, "checkTempAppWhitelistTimeout: appId=" + appId + ", timeNow=" + timeNow); } synchronized (this) { - Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(uid); + Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(appId); if (entry == null) { // Nothing to do return; } if (timeNow >= entry.first.value) { - mTempWhitelistAppIdEndTimes.delete(uid); - onAppRemovedFromTempWhitelistLocked(uid, entry.second); + mTempWhitelistAppIdEndTimes.delete(appId); + onAppRemovedFromTempWhitelistLocked(appId, entry.second); } else { // Need more time if (DEBUG) { - Slog.d(TAG, "Time to remove UID " + uid + ": " + entry.first.value); + Slog.d(TAG, "Time to remove AppId " + appId + ": " + entry.first.value); } - postTempActiveTimeoutMessage(uid, entry.first.value - timeNow); + postTempActiveTimeoutMessage(appId, entry.first.value - timeNow); } } } diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index f1882c5f641e..9d979a6701c7 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -18,16 +18,23 @@ package com.android.server; import android.content.Context; import android.content.pm.PackageManager; +import android.gsi.GsiInstallParams; import android.gsi.GsiProgress; import android.gsi.IGsiService; +import android.os.Environment; import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; +import android.os.UserHandle; import android.os.image.IDynamicSystemService; +import android.os.storage.StorageManager; +import android.os.storage.StorageVolume; import android.util.Slog; +import java.io.File; + /** * DynamicSystemService implements IDynamicSystemService. It provides permission check before * passing requests to gsid @@ -36,7 +43,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements private static final String TAG = "DynamicSystemService"; private static final String NO_SERVICE_ERROR = "no gsiservice"; private static final int GSID_ROUGH_TIMEOUT_MS = 8192; - + private static final String PATH_DEFAULT = "/data/gsi"; private Context mContext; private volatile IGsiService mGsiService; @@ -105,7 +112,32 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements @Override public boolean startInstallation(long systemSize, long userdataSize) throws RemoteException { - return getGsiService().startGsiInstall(systemSize, userdataSize, true) == 0; + // priority from high to low: sysprop -> sdcard -> /data + String path = SystemProperties.get("os.aot.path"); + if (path.isEmpty()) { + final int userId = UserHandle.myUserId(); + final StorageVolume[] volumes = + StorageManager.getVolumeList(userId, StorageManager.FLAG_FOR_WRITE); + for (StorageVolume volume : volumes) { + if (volume.isEmulated()) continue; + if (!volume.isRemovable()) continue; + if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue; + File sdCard = volume.getPathFile(); + if (sdCard.isDirectory()) { + path = sdCard.getPath(); + break; + } + } + if (path.isEmpty()) { + path = PATH_DEFAULT; + } + Slog.i(TAG, "startInstallation -> " + path); + } + GsiInstallParams installParams = new GsiInstallParams(); + installParams.installDir = path; + installParams.gsiSize = systemSize; + installParams.userdataSize = userdataSize; + return getGsiService().beginGsiInstall(installParams) == 0; } @Override diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index da9cffa73585..82bba779e69b 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1693,9 +1693,6 @@ class StorageManagerService extends IStorageManager.Stub // Always remember the new state we just booted with writeSettingsLocked(); } - - // Execute special logic to recover certain devices - recoverFrom128872367(); } } @@ -1756,69 +1753,6 @@ class StorageManagerService extends IStorageManager.Stub return maxTime; } - /** - * In b/128872367 we lost all app-ops on devices in the wild. This logic - * attempts to detect and recover from this by granting - * {@link AppOpsManager#OP_LEGACY_STORAGE} to any apps installed before - * isolated storage was enabled. - */ - private void recoverFrom128872367() { - // We're interested in packages that were installed or updated between - // 1/1/2014 and 12/17/2018 - final long START_TIMESTAMP = 1388534400000L; - final long END_TIMESTAMP = 1545004800000L; - - final PackageManager pm = mContext.getPackageManager(); - final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); - final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); - - boolean activeDuringWindow = false; - List<PackageInfo> pendingHolders = new ArrayList<>(); - - for (int userId : um.getUserIds()) { - final List<PackageInfo> pkgs = pm.getInstalledPackagesAsUser(MATCH_UNINSTALLED_PACKAGES - | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); - for (PackageInfo pkg : pkgs) { - // Determine if any apps on this device had been installed or - // updated during the period where the feature was disabled - activeDuringWindow |= (pkg.firstInstallTime > START_TIMESTAMP - && pkg.firstInstallTime < END_TIMESTAMP); - activeDuringWindow |= (pkg.lastUpdateTime > START_TIMESTAMP - && pkg.lastUpdateTime < END_TIMESTAMP); - - // This app should hold legacy op if they were installed before - // the cutoff; we only check the end boundary here so that - // include system apps, which are always installed on 1/1/2009. - final boolean shouldHold = (pkg.firstInstallTime < END_TIMESTAMP); - final boolean doesHold = (appOps.checkOpNoThrow(OP_LEGACY_STORAGE, - pkg.applicationInfo.uid, - pkg.applicationInfo.packageName) == MODE_ALLOWED); - - if (doesHold) { - Slog.d(TAG, "Found " + pkg + " holding legacy op; skipping recovery"); - return; - } else if (shouldHold) { - Slog.d(TAG, "Found " + pkg + " that should hold legacy op"); - pendingHolders.add(pkg); - } - } - } - - if (!activeDuringWindow) { - Slog.d(TAG, "No packages were active during the time window; skipping grants"); - return; - } - - // If we made it this far, nobody actually holds the legacy op, which - // means we probably lost the database, and we should grant the op to - // all the apps we identified. - for (PackageInfo pkg : pendingHolders) { - appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE, - pkg.applicationInfo.uid, - pkg.applicationInfo.packageName, AppOpsManager.MODE_ALLOWED); - } - } - private void systemReady() { LocalServices.getService(ActivityTaskManagerInternal.class) .registerScreenObserver(this); @@ -3832,7 +3766,7 @@ class StorageManagerService extends IStorageManager.Stub return Zygote.MOUNT_EXTERNAL_NONE; } if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) { - return Zygote.MOUNT_EXTERNAL_NONE; + return Zygote.MOUNT_EXTERNAL_DEFAULT; } // Determine if caller is holding runtime permission diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java index f74a438509c2..dab6bc4bbfb0 100644 --- a/services/core/java/com/android/server/ThreadPriorityBooster.java +++ b/services/core/java/com/android/server/ThreadPriorityBooster.java @@ -26,6 +26,7 @@ import static android.os.Process.setThreadPriority; public class ThreadPriorityBooster { private static final boolean ENABLE_LOCK_GUARD = false; + private static final int PRIORITY_NOT_ADJUSTED = Integer.MAX_VALUE; private volatile int mBoostToPriority; private final int mLockGuardIndex; @@ -42,13 +43,12 @@ public class ThreadPriorityBooster { } public void boost() { - final int tid = myTid(); final PriorityState state = mThreadState.get(); if (state.regionCounter == 0) { - final int prevPriority = getThreadPriority(tid); - state.prevPriority = prevPriority; + final int prevPriority = getThreadPriority(state.tid); if (prevPriority > mBoostToPriority) { - setThreadPriority(tid, mBoostToPriority); + setThreadPriority(state.tid, mBoostToPriority); + state.prevPriority = prevPriority; } } state.regionCounter++; @@ -60,11 +60,9 @@ public class ThreadPriorityBooster { public void reset() { final PriorityState state = mThreadState.get(); state.regionCounter--; - if (state.regionCounter == 0) { - final int currentPriority = getThreadPriority(myTid()); - if (state.prevPriority != currentPriority) { - setThreadPriority(myTid(), state.prevPriority); - } + if (state.regionCounter == 0 && state.prevPriority != PRIORITY_NOT_ADJUSTED) { + setThreadPriority(state.tid, state.prevPriority); + state.prevPriority = PRIORITY_NOT_ADJUSTED; } } @@ -78,16 +76,16 @@ public class ThreadPriorityBooster { // variable immediately. mBoostToPriority = priority; final PriorityState state = mThreadState.get(); - final int tid = myTid(); if (state.regionCounter != 0) { - final int prevPriority = getThreadPriority(tid); + final int prevPriority = getThreadPriority(state.tid); if (prevPriority != priority) { - setThreadPriority(tid, priority); + setThreadPriority(state.tid, priority); } } } private static class PriorityState { + final int tid = myTid(); /** * Acts as counter for number of synchronized region that needs to acquire 'this' as a lock @@ -99,6 +97,6 @@ public class ThreadPriorityBooster { /** * The thread's previous priority before boosting. */ - int prevPriority; + int prevPriority = PRIORITY_NOT_ADJUSTED; } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f0982d3aa142..4ec90ba5b803 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2117,6 +2117,12 @@ public final class ActiveServices { Slog.w(TAG, "Service lookup failed: " + msg); return new ServiceLookupResult(null, msg); } + + // Store the defining packageName and uid, as they might be changed in + // the ApplicationInfo for external services (which run with the package name + // and uid of the caller). + String definingPackageName = sInfo.applicationInfo.packageName; + int definingUid = sInfo.applicationInfo.uid; if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) { if (isBindExternal) { if (!sInfo.exported) { @@ -2175,8 +2181,8 @@ public final class ActiveServices { sInfo.applicationInfo.uid, name.getPackageName(), name.getClassName()); } - r = new ServiceRecord(mAm, ss, className, name, filter, sInfo, - callingFromFg, res); + r = new ServiceRecord(mAm, ss, className, name, definingPackageName, + definingUid, filter, sInfo, callingFromFg, res); res.setService(r); smap.mServicesByInstanceName.put(name, r); smap.mServicesByIntent.put(filter, r); @@ -2557,7 +2563,7 @@ public final class ActiveServices { final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0; final String procName = r.processName; - String hostingType = "service"; + HostingRecord hostingRecord = new HostingRecord("service", r.instanceName); ProcessRecord app; if (!isolated) { @@ -2588,10 +2594,11 @@ public final class ActiveServices { app = r.isolatedProc; if (WebViewZygote.isMultiprocessEnabled() && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) { - hostingType = "webview_service"; + hostingRecord = HostingRecord.byWebviewZygote(r.instanceName); } if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) { - hostingType = "app_zygote"; + hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName, + r.definingUid); } } @@ -2599,7 +2606,7 @@ public final class ActiveServices { // to be executed when the app comes up. if (app == null && !permissionsReviewRequired) { if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, - hostingType, r.instanceName, false, isolated, false)) == null) { + hostingRecord, false, isolated, false)) == null) { String msg = "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0b9e3bb1b99e..3b6b404170c5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1498,6 +1498,7 @@ public class ActivityManagerService extends IActivityManager.Stub private ParcelFileDescriptor[] mLifeMonitorFds; + static final HostingRecord sNullHostingRecord = new HostingRecord(null); /** * Used to notify activity lifecycle events. */ @@ -1963,7 +1964,7 @@ public class ActivityManagerService extends IActivityManager.Stub ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName, false, 0, - false); + new HostingRecord("system")); app.setPersistent(true); app.pid = MY_PID; app.getWindowProcessController().setPid(MY_PID); @@ -2894,8 +2895,9 @@ public class ActivityManagerService extends IActivityManager.Stub info.seInfoUser = SELinuxUtil.COMPLETE_STR; info.targetSdkVersion = Build.VERSION.SDK_INT; ProcessRecord proc = mProcessList.startProcessLocked(processName, info /* info */, - false /* knownToBeDead */, 0 /* intentFlags */, "" /* hostingType */, - null /* hostingName */, true /* allowWhileBooting */, true /* isolated */, + false /* knownToBeDead */, 0 /* intentFlags */, + sNullHostingRecord /* hostingRecord */, + true /* allowWhileBooting */, true /* isolated */, uid, true /* keepIfLarge */, abiOverride, entryPoint, entryPointArgs, crashHandler); return proc != null; @@ -2905,11 +2907,10 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, - String hostingType, ComponentName hostingName, boolean allowWhileBooting, + HostingRecord hostingRecord, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags, - hostingType, - hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, + hostingRecord, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); } @@ -4692,7 +4693,8 @@ public class ActivityManagerService extends IActivityManager.Stub app.deathRecipient = adr; } catch (RemoteException e) { app.resetPackageList(mProcessStats); - mProcessList.startProcessLocked(app, "link fail", processName); + mProcessList.startProcessLocked(app, + new HostingRecord("link fail", processName)); return false; } @@ -4931,7 +4933,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.resetPackageList(mProcessStats); app.unlinkDeathRecipient(); - mProcessList.startProcessLocked(app, "bind fail", processName); + mProcessList.startProcessLocked(app, new HostingRecord("bind-fail", processName)); return false; } @@ -5013,8 +5015,8 @@ public class ActivityManagerService extends IActivityManager.Stub app.startTime, (int) (bindApplicationTimeMillis - app.startTime), (int) (SystemClock.elapsedRealtime() - app.startTime), - app.hostingType, - (app.hostingNameStr != null ? app.hostingNameStr : "")); + app.hostingRecord.getType(), + (app.hostingRecord.getName() != null ? app.hostingRecord.getName() : "")); return true; } @@ -5123,7 +5125,7 @@ public class ActivityManagerService extends IActivityManager.Stub for (int ip=0; ip<NP; ip++) { if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Starting process on hold: " + procs.get(ip)); - mProcessList.startProcessLocked(procs.get(ip), "on-hold", null); + mProcessList.startProcessLocked(procs.get(ip), new HostingRecord("on-hold")); } } if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) { @@ -6915,9 +6917,10 @@ public class ActivityManagerService extends IActivityManager.Stub } else { checkTime(startTime, "getContentProviderImpl: before start process"); proc = startProcessLocked(cpi.processName, - cpr.appInfo, false, 0, "content provider", + cpr.appInfo, false, 0, + new HostingRecord("content provider", new ComponentName(cpi.applicationInfo.packageName, - cpi.name), false, false, false); + cpi.name)), false, false, false); checkTime(startTime, "getContentProviderImpl: after start process"); if (proc == null) { Slog.w(TAG, "Unable to launch app " @@ -7638,7 +7641,9 @@ public class ActivityManagerService extends IActivityManager.Stub } if (app == null) { - app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, false); + app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, + new HostingRecord("added application", + customProcess != null ? customProcess : info.processName)); mProcessList.updateLruProcessLocked(app, false, null); updateOomAdjLocked(); } @@ -7659,9 +7664,9 @@ public class ActivityManagerService extends IActivityManager.Stub } if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); - mProcessList.startProcessLocked(app, "added application", - customProcess != null ? customProcess : app.processName, disableHiddenApiChecks, - mountExtStorageFull, abiOverride); + mProcessList.startProcessLocked(app, new HostingRecord("added application", + customProcess != null ? customProcess : app.processName), + disableHiddenApiChecks, mountExtStorageFull, abiOverride); } return app; @@ -13611,7 +13616,8 @@ public class ActivityManagerService extends IActivityManager.Stub } mProcessList.addProcessNameLocked(app); app.pendingStart = false; - mProcessList.startProcessLocked(app, "restart", app.processName); + mProcessList.startProcessLocked(app, + new HostingRecord("restart", app.processName)); return true; } else if (app.pid > 0 && app.pid != MY_PID) { // Goodbye! @@ -13952,9 +13958,12 @@ public class ActivityManagerService extends IActivityManager.Stub (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL) ? new ComponentName(app.packageName, app.backupAgentName) : new ComponentName("android", "FullBackupAgent"); + // startProcessLocked() returns existing proc's record if it's already running ProcessRecord proc = startProcessLocked(app.processName, app, - false, 0, "backup", hostingName, false, false, false); + false, 0, + new HostingRecord("backup", hostingName), + false, false, false); if (proc == null) { Slog.e(TAG, "Unable to start backup agent process " + r); return false; @@ -18163,8 +18172,9 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (ActivityManagerService.this) { startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */, - hostingType, hostingName, false /* allowWhileBooting */, - false /* isolated */, true /* keepIfLarge */); + new HostingRecord(hostingType, hostingName), + false /* allowWhileBooting */, false /* isolated */, + true /* keepIfLarge */); } } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 4bfbb78e4187..3c57c3bcb7d6 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1623,7 +1623,7 @@ public final class BroadcastQueue { if ((r.curApp=mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, - "broadcast", r.curComponent, + new HostingRecord("broadcast", r.curComponent), (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) { // Ah, this recipient is unavailable. Finish it if necessary, diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java new file mode 100644 index 000000000000..784dde1e98df --- /dev/null +++ b/services/core/java/com/android/server/am/HostingRecord.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.content.ComponentName; + +/** + * This class describes various information required to start a process. + * + * The {@code mHostingType} field describes the reason why we started a process, and + * is only used for logging and stats. + * + * The {@code mHostingName} field describes the Component for which we are starting the + * process, and is only used for logging and stats. + * + * The {@code mHostingZygote} field describes from which Zygote the new process should be spawned. + * + * {@code mDefiningPackageName} contains the packageName of the package that defines the + * component we want to start; this can be different from the packageName and uid in the + * ApplicationInfo that we're creating the process with, in case the service is a + * {@link android.content.Context#BIND_EXTERNAL_SERVICE} service. In that case, the packageName + * and uid in the ApplicationInfo will be set to those of the caller, not of the defining package. + * + * {@code mDefiningUid} contains the uid of the application that defines the component we want to + * start; this can be different from the packageName and uid in the ApplicationInfo that we're + * creating the process with, in case the service is a + * {@link android.content.Context#BIND_EXTERNAL_SERVICE} service. In that case, the packageName + * and uid in the ApplicationInfo will be set to those of the caller, not of the defining package. + * + */ + +public final class HostingRecord { + private static final int REGULAR_ZYGOTE = 0; + private static final int WEBVIEW_ZYGOTE = 1; + private static final int APP_ZYGOTE = 2; + + private final String mHostingType; + private final String mHostingName; + private final int mHostingZygote; + private final String mDefiningPackageName; + private final int mDefiningUid; + + public HostingRecord(String hostingType) { + this(hostingType, null, REGULAR_ZYGOTE, null, -1); + } + + public HostingRecord(String hostingType, ComponentName hostingName) { + this(hostingType, hostingName, REGULAR_ZYGOTE); + } + + public HostingRecord(String hostingType, String hostingName) { + this(hostingType, hostingName, REGULAR_ZYGOTE); + } + + private HostingRecord(String hostingType, ComponentName hostingName, int hostingZygote) { + this(hostingType, hostingName.toShortString(), hostingZygote); + } + + private HostingRecord(String hostingType, String hostingName, int hostingZygote) { + this(hostingType, hostingName, hostingZygote, null, -1); + } + + private HostingRecord(String hostingType, String hostingName, int hostingZygote, + String definingPackageName, int definingUid) { + mHostingType = hostingType; + mHostingName = hostingName; + mHostingZygote = hostingZygote; + mDefiningPackageName = definingPackageName; + mDefiningUid = definingUid; + } + + public String getType() { + return mHostingType; + } + + public String getName() { + return mHostingName; + } + + /** + * Returns the UID of the package defining the component we want to start. Only valid + * when {@link #usesAppZygote()} returns true. + * + * @return the UID of the hosting application + */ + public int getDefiningUid() { + return mDefiningUid; + } + + /** + * Returns the packageName of the package defining the component we want to start. Only valid + * when {@link #usesAppZygote()} returns true. + * + * @return the packageName of the hosting application + */ + public String getDefiningPackageName() { + return mDefiningPackageName; + } + + /** + * Creates a HostingRecord for a process that must spawn from the webview zygote + * @param hostingName name of the component to be hosted in this process + * @return The constructed HostingRecord + */ + public static HostingRecord byWebviewZygote(ComponentName hostingName) { + return new HostingRecord("", hostingName.toShortString(), WEBVIEW_ZYGOTE); + } + + /** + * Creates a HostingRecord for a process that must spawn from the application zygote + * @param hostingName name of the component to be hosted in this process + * @param definingPackageName name of the package defining the service + * @param definingUid uid of the package defining the service + * @return The constructed HostingRecord + */ + public static HostingRecord byAppZygote(ComponentName hostingName, String definingPackageName, + int definingUid) { + return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE, + definingPackageName, definingUid); + } + + /** + * @return whether the process should spawn from the application zygote + */ + public boolean usesAppZygote() { + return mHostingZygote == APP_ZYGOTE; + } + + /** + * @return whether the process should spawn from the webview zygote + */ + public boolean usesWebviewZygote() { + return mHostingZygote == WEBVIEW_ZYGOTE; + } +} diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index a08c829f0576..588e05d7a060 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -29,6 +29,7 @@ import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; +import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.TransactionTooLargeException; @@ -380,8 +381,9 @@ public final class PendingIntentRecord extends IIntentSender.Stub { userId = controller.mUserController.getCurrentOrTargetUserId(); } // temporarily allow receivers and services to open activities from background if the - // PendingIntent.send() caller was foreground at the time of sendInner() call - final boolean allowTrampoline = uid != callingUid + // PendingIntent.send() caller was foreground at the time of sendInner() call, unless + // caller is SYSTEM_UID + final boolean allowTrampoline = uid != callingUid && callingUid != Process.SYSTEM_UID && controller.mAtmInternal.isUidForeground(callingUid); // note: we on purpose don't pass in the information about the PendingIntent's creator, diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 9780a7f71970..0a926f9a801a 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -454,13 +454,13 @@ public final class ProcessList { } @GuardedBy("ProcessList.this.mService") - IsolatedUidRange getIsolatedUidRangeLocked(ApplicationInfo info) { - return mAppRanges.get(info.processName, info.uid); + IsolatedUidRange getIsolatedUidRangeLocked(String processName, int uid) { + return mAppRanges.get(processName, uid); } @GuardedBy("ProcessList.this.mService") - IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info) { - IsolatedUidRange range = getIsolatedUidRangeLocked(info); + IsolatedUidRange getOrCreateIsolatedUidRangeLocked(String processName, int uid) { + IsolatedUidRange range = getIsolatedUidRangeLocked(processName, uid); if (range == null) { int uidRangeIndex = mAvailableUidRanges.nextSetBit(0); if (uidRangeIndex < 0) { @@ -470,7 +470,7 @@ public final class ProcessList { mAvailableUidRanges.clear(uidRangeIndex); int actualUid = mFirstUid + uidRangeIndex * mNumUidsPerRange; range = new IsolatedUidRange(actualUid, actualUid + mNumUidsPerRange - 1); - mAppRanges.put(info.processName, info.uid, range); + mAppRanges.put(processName, uid, range); } return range; } @@ -1427,14 +1427,13 @@ public final class ProcessList { /** * @return {@code true} if process start is successful, false otherwise. * @param app - * @param hostingType - * @param hostingNameStr + * @param hostingRecord * @param disableHiddenApiChecks * @param abiOverride */ @GuardedBy("mService") - boolean startProcessLocked(ProcessRecord app, String hostingType, - String hostingNameStr, boolean disableHiddenApiChecks, boolean mountExtStorageFull, + boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, + boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride) { if (app.pendingStart) { return true; @@ -1625,7 +1624,7 @@ public final class ProcessList { // the PID of the new process, or else throw a RuntimeException. final String entryPoint = "android.app.ActivityThread"; - return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids, + return startProcessLocked(hostingRecord, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); } catch (RuntimeException e) { @@ -1644,7 +1643,7 @@ public final class ProcessList { } @GuardedBy("mService") - boolean startProcessLocked(String hostingType, String hostingNameStr, + boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, @@ -1654,7 +1653,7 @@ public final class ProcessList { app.removed = false; app.killed = false; final long startSeq = app.startSeq = ++mProcStartSeqCounter; - app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime); + app.setStartParams(uid, hostingRecord, seInfo, startTime); if (mService.mConstants.FLAG_PROCESS_START_ASYNC) { if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES, "Posting procStart msg for " + app.toShortString()); @@ -1672,7 +1671,7 @@ public final class ProcessList { || SystemProperties.get("wrap." + app.processName) != null); mPendingStarts.put(startSeq, app); } - final Process.ProcessStartResult startResult = startProcess(app.hostingType, + final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (mService) { @@ -1693,7 +1692,7 @@ public final class ProcessList { return true; } else { try { - final Process.ProcessStartResult startResult = startProcess(hostingType, + final Process.ProcessStartResult startResult = startProcess(hostingRecord, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); @@ -1727,12 +1726,14 @@ public final class ProcessList { private void removeProcessFromAppZygoteLocked(final ProcessRecord app) { // Free the isolated uid for this process final IsolatedUidRange appUidRange = - mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info); + mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info.processName, + app.hostingRecord.getDefiningUid()); if (appUidRange != null) { appUidRange.freeIsolatedUidLocked(app.uid); } - final AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid); + final AppZygote appZygote = mAppZygotes.get(app.info.processName, + app.hostingRecord.getDefiningUid()); if (appZygote != null) { ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote); zygoteProcesses.remove(app); @@ -1753,21 +1754,40 @@ public final class ProcessList { private AppZygote createAppZygoteForProcessIfNeeded(final ProcessRecord app) { synchronized (mService) { - AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid); + // The UID for the app zygote should be the UID of the application hosting + // the service. + final int uid = app.hostingRecord.getDefiningUid(); + AppZygote appZygote = mAppZygotes.get(app.info.processName, uid); final ArrayList<ProcessRecord> zygoteProcessList; if (appZygote == null) { + if (DEBUG_PROCESSES) { + Slog.d(TAG_PROCESSES, "Creating new app zygote."); + } final IsolatedUidRange uidRange = - mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info); - final int userId = UserHandle.getUserId(app.info.uid); + mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked( + app.info.processName, app.hostingRecord.getDefiningUid()); + final int userId = UserHandle.getUserId(uid); // Create the app-zygote and provide it with the UID-range it's allowed // to setresuid/setresgid to. final int firstUid = UserHandle.getUid(userId, uidRange.mFirstUid); final int lastUid = UserHandle.getUid(userId, uidRange.mLastUid); - appZygote = new AppZygote(app.info, app.info.uid, firstUid, lastUid); - mAppZygotes.put(app.info.processName, app.info.uid, appZygote); + ApplicationInfo appInfo = new ApplicationInfo(app.info); + // If this was an external service, the package name and uid in the passed in + // ApplicationInfo have been changed to match those of the calling package; + // that is not what we want for the AppZygote though, which needs to have the + // packageName and uid of the defining application. This is because the + // preloading only makes sense in the context of the defining application, + // not the calling one. + appInfo.packageName = app.hostingRecord.getDefiningPackageName(); + appInfo.uid = uid; + appZygote = new AppZygote(appInfo, uid, firstUid, lastUid); + mAppZygotes.put(app.info.processName, uid, appZygote); zygoteProcessList = new ArrayList<ProcessRecord>(); mAppZygoteProcesses.put(appZygote, zygoteProcessList); } else { + if (DEBUG_PROCESSES) { + Slog.d(TAG_PROCESSES, "Reusing existing app zygote."); + } mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG, appZygote); zygoteProcessList = mAppZygoteProcesses.get(appZygote); } @@ -1781,7 +1801,7 @@ public final class ProcessList { } } - private Process.ProcessStartResult startProcess(String hostingType, String entryPoint, + private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { @@ -1797,7 +1817,7 @@ public final class ProcessList { app.processName); checkSlow(startTime, "startProcess: asking zygote to start proc"); final Process.ProcessStartResult startResult; - if (hostingType.equals("webview_service")) { + if (hostingRecord.usesWebviewZygote()) { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, @@ -1805,7 +1825,7 @@ public final class ProcessList { packageNames, sandboxId, new String[] {PROC_START_SEQ_IDENT + app.startSeq}, useSystemGraphicsDriver); - } else if (hostingType.equals("app_zygote")) { + } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); startResult = appZygote.getProcess().start(entryPoint, @@ -1832,21 +1852,20 @@ public final class ProcessList { } @GuardedBy("mService") - final void startProcessLocked(ProcessRecord app, - String hostingType, String hostingNameStr) { - startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */); + final void startProcessLocked(ProcessRecord app, HostingRecord hostingRecord) { + startProcessLocked(app, hostingRecord, null /* abiOverride */); } @GuardedBy("mService") - final boolean startProcessLocked(ProcessRecord app, - String hostingType, String hostingNameStr, String abiOverride) { - return startProcessLocked(app, hostingType, hostingNameStr, + final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, + String abiOverride) { + return startProcessLocked(app, hostingRecord, false /* disableHiddenApiChecks */, false /* mountExtStorageFull */, abiOverride); } @GuardedBy("mService") final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, - boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, + boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { long startTime = SystemClock.elapsedRealtime(); @@ -1916,13 +1935,9 @@ public final class ProcessList { checkSlow(startTime, "startProcess: done killing old proc"); } - String hostingNameStr = hostingName != null - ? hostingName.flattenToShortString() : null; - if (app == null) { - final boolean fromAppZygote = "app_zygote".equals(hostingType); checkSlow(startTime, "startProcess: creating new process record"); - app = newProcessRecordLocked(info, processName, isolated, isolatedUid, fromAppZygote); + app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord); if (app == null) { Slog.w(TAG, "Failed making new process record for " + processName + "/" + info.uid + " isolated=" + isolated); @@ -1953,8 +1968,7 @@ public final class ProcessList { } checkSlow(startTime, "startProcess: stepping in to startProcess"); - final boolean success = startProcessLocked(app, hostingType, hostingNameStr, - abiOverride); + final boolean success = startProcessLocked(app, hostingRecord, abiOverride); checkSlow(startTime, "startProcess: done starting proc!"); return success ? app : null; } @@ -2015,8 +2029,8 @@ public final class ProcessList { EventLog.writeEvent(EventLogTags.AM_PROC_START, UserHandle.getUserId(app.startUid), pid, app.startUid, - app.processName, app.hostingType, - app.hostingNameStr != null ? app.hostingNameStr : ""); + app.processName, app.hostingRecord.getType(), + app.hostingRecord.getName() != null ? app.hostingRecord.getName() : ""); try { AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid, @@ -2044,10 +2058,10 @@ public final class ProcessList { buf.append("]"); } buf.append(" for "); - buf.append(app.hostingType); - if (app.hostingNameStr != null) { + buf.append(app.hostingRecord.getType()); + if (app.hostingRecord.getName() != null) { buf.append(" "); - buf.append(app.hostingNameStr); + buf.append(app.hostingRecord.getName()); } mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid); app.setPid(pid); @@ -2307,24 +2321,25 @@ public final class ProcessList { @GuardedBy("mService") private IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info, - boolean fromAppZygote) { - if (!fromAppZygote) { + HostingRecord hostingRecord) { + if (hostingRecord == null || !hostingRecord.usesAppZygote()) { // Allocate an isolated UID from the global range return mGlobalIsolatedUids; } else { - return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked(info); + return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked( + info.processName, hostingRecord.getDefiningUid()); } } @GuardedBy("mService") final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, - boolean isolated, int isolatedUid, boolean fromAppZygote) { + boolean isolated, int isolatedUid, HostingRecord hostingRecord) { String proc = customProcess != null ? customProcess : info.processName; final int userId = UserHandle.getUserId(info.uid); int uid = info.uid; if (isolated) { if (isolatedUid == 0) { - IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, fromAppZygote); + IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, hostingRecord); if (uidRange == null) { return null; } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index ce13cd88a192..933f41c47167 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -301,18 +301,16 @@ class ProcessRecord implements WindowProcessListener { boolean whitelistManager; // Params used in starting this process. - String hostingType; - String hostingNameStr; + HostingRecord hostingRecord; String seInfo; long startTime; // This will be same as {@link #uid} usually except for some apps used during factory testing. int startUid; - void setStartParams(int startUid, String hostingType, String hostingNameStr, String seInfo, + void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startTime) { this.startUid = startUid; - this.hostingType = hostingType; - this.hostingNameStr = hostingNameStr; + this.hostingRecord = hostingRecord; this.seInfo = seInfo; this.startTime = startTime; } @@ -878,13 +876,6 @@ class ProcessRecord implements WindowProcessListener { return null; } - @Override - public void addPackage(String pkg, long versionCode) { - synchronized (mService) { - addPackage(pkg, versionCode, mService.mProcessStats); - } - } - /* * Return true if package has been added false if not */ @@ -1302,15 +1293,13 @@ class ProcessRecord implements WindowProcessListener { } @Override - public void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru, - boolean activityChange, boolean updateOomAdj) { + public void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange, + boolean updateOomAdj) { synchronized (mService) { if (updateServiceConnectionActivities) { mService.mServices.updateServiceConnectionActivitiesLocked(this); } - if (updateLru) { - mService.mProcessList.updateLruProcessLocked(this, activityChange, null); - } + mService.mProcessList.updateLruProcessLocked(this, activityChange, null /* client */); if (updateOomAdj) { mService.updateOomAdjLocked(); } @@ -1332,19 +1321,20 @@ class ProcessRecord implements WindowProcessListener { } @Override - public void clearWaitingToKill() { + public void onStartActivity(int topProcessState, boolean setProfileProc, String packageName, + long versionCode) { synchronized (mService) { waitingToKill = null; - } - } - - @Override - public void onStartActivity(int topProcessState, boolean setProfileProc) { - synchronized (mService) { if (setProfileProc) { mService.mProfileData.setProfileProc(this); } + if (packageName != null) { + addPackage(packageName, versionCode, mService.mProcessStats); + } + // Update oom adj first, we don't want the additional states are involved in this round. + updateProcessInfo(false /* updateServiceConnectionActivities */, + true /* activityChange */, true /* updateOomAdj */); hasShownUi = true; setPendingUiClean(true); forceProcessStateUpTo(topProcessState); diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 217fd6d71888..27c62d03f960 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -73,6 +73,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN final ComponentName name; // service component. final ComponentName instanceName; // service component's per-instance name. final String shortInstanceName; // instanceName.flattenToShortString(). + final String definingPackageName; + // Can be different from appInfo.packageName for external services + final int definingUid; + // Can be different from appInfo.uid for external services final Intent.FilterComparison intent; // original intent used to find service. final ServiceInfo serviceInfo; @@ -474,7 +478,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN ServiceRecord(ActivityManagerService ams, BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name, - ComponentName instanceName, + ComponentName instanceName, String definingPackageName, int definingUid, Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg, Runnable restarter) { this.ams = ams; @@ -482,6 +486,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN this.name = name; this.instanceName = instanceName; shortInstanceName = instanceName.flattenToShortString(); + this.definingPackageName = definingPackageName; + this.definingUid = definingUid; this.intent = intent; serviceInfo = sInfo; appInfo = sInfo.applicationInfo; diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 4c3bb8c07728..873cadb5a9d9 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -220,7 +220,8 @@ public class AppOpsService extends IAppOpsService.Stub { * global Settings. Any access to this class or its fields should be done while * holding the AppOpsService lock. */ - private final class Constants extends ContentObserver { + @VisibleForTesting + final class Constants extends ContentObserver { // Key names stored in the settings value. private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time"; private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME @@ -305,7 +306,8 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private final Constants mConstants; + @VisibleForTesting + final Constants mConstants; @VisibleForTesting static final class UidState { diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 3dbea0d1978e..d7d4851bf33f 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -17,7 +17,6 @@ package com.android.server.attention; import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; -import static android.provider.Settings.System.ADAPTIVE_SLEEP; import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED; import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; @@ -47,7 +46,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.DeviceConfig; -import android.provider.Settings; import android.service.attention.AttentionService; import android.service.attention.AttentionService.AttentionFailureCodes; import android.service.attention.AttentionService.AttentionSuccessCodes; @@ -60,6 +58,7 @@ import android.util.StatsLog; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; @@ -102,16 +101,25 @@ public class AttentionManagerService extends SystemService { private final Object mLock; @GuardedBy("mLock") private final SparseArray<UserState> mUserStates = new SparseArray<>(); - private final AttentionHandler mAttentionHandler; + private AttentionHandler mAttentionHandler; - private ComponentName mComponentName; + @VisibleForTesting + ComponentName mComponentName; public AttentionManagerService(Context context) { + this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE), + new Object(), null); + mAttentionHandler = new AttentionHandler(); + } + + @VisibleForTesting + AttentionManagerService(Context context, PowerManager powerManager, Object lock, + AttentionHandler handler) { super(context); mContext = Preconditions.checkNotNull(context); - mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mLock = new Object(); - mAttentionHandler = new AttentionHandler(); + mPowerManager = powerManager; + mLock = lock; + mAttentionHandler = handler; } @Override @@ -149,7 +157,8 @@ public class AttentionManagerService extends SystemService { return isServiceEnabled() && isServiceAvailable(); } - private boolean isServiceEnabled() { + @VisibleForTesting + protected boolean isServiceEnabled() { return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, SERVICE_ENABLED, DEFAULT_SERVICE_ENABLED); } @@ -163,7 +172,8 @@ public class AttentionManagerService extends SystemService { * * @return {@code true} if the framework was able to dispatch the request */ - private boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) { + @VisibleForTesting + boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) { Preconditions.checkNotNull(callbackInternal); if (!isAttentionServiceSupported()) { @@ -259,37 +269,24 @@ public class AttentionManagerService extends SystemService { } /** Cancels the specified attention check. */ - private void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { + @VisibleForTesting + void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { synchronized (mLock) { final UserState userState = peekCurrentUserStateLocked(); if (userState == null) { return; } - if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) { Slog.e(LOG_TAG, "Cannot cancel a non-current request"); return; } - cancel(userState); } } - /** Disables service dependants. */ - private void disableSelf() { - final long identity = Binder.clearCallingIdentity(); - try { - if (DEBUG) { - Slog.d(LOG_TAG, "Disabling self."); - } - Settings.System.putInt(mContext.getContentResolver(), ADAPTIVE_SLEEP, 0); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - @GuardedBy("mLock") - private void freeIfInactiveLocked() { + @VisibleForTesting + protected void freeIfInactiveLocked() { // If we are called here, it means someone used the API again - reset the timer then. mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION); @@ -306,7 +303,8 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") - private UserState getOrCreateCurrentUserStateLocked() { + @VisibleForTesting + protected UserState getOrCreateCurrentUserStateLocked() { return getOrCreateUserStateLocked(ActivityManager.getCurrentUser()); } @@ -322,7 +320,8 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") @Nullable - private UserState peekCurrentUserStateLocked() { + @VisibleForTesting + protected UserState peekCurrentUserStateLocked() { return peekUserStateLocked(ActivityManager.getCurrentUser()); } @@ -418,11 +417,6 @@ public class AttentionManagerService extends SystemService { public void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { AttentionManagerService.this.cancelAttentionCheck(callbackInternal); } - - @Override - public void disableSelf() { - AttentionManagerService.this.disableSelf(); - } } private static final class AttentionCheckCache { @@ -438,7 +432,8 @@ public class AttentionManagerService extends SystemService { } } - private static final class AttentionCheck { + @VisibleForTesting + static final class AttentionCheck { private final AttentionCallbackInternal mCallbackInternal; private final IAttentionCallback mIAttentionCallback; private boolean mIsDispatched; @@ -455,7 +450,8 @@ public class AttentionManagerService extends SystemService { } } - private static final class UserState { + @VisibleForTesting + protected static class UserState { final ComponentName mComponentName; final AttentionServiceConnection mConnection = new AttentionServiceConnection(); @@ -473,7 +469,7 @@ public class AttentionManagerService extends SystemService { final Context mContext; final Object mLock; - private UserState(int userId, Context context, Object lock, ComponentName componentName) { + UserState(int userId, Context context, Object lock, ComponentName componentName) { mUserId = userId; mContext = Preconditions.checkNotNull(context); mLock = Preconditions.checkNotNull(lock); @@ -529,7 +525,7 @@ public class AttentionManagerService extends SystemService { } } - private final class AttentionServiceConnection implements ServiceConnection { + private class AttentionServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { init(IAttentionService.Stub.asInterface(service)); @@ -564,7 +560,8 @@ public class AttentionManagerService extends SystemService { } } - private class AttentionHandler extends Handler { + @VisibleForTesting + protected class AttentionHandler extends Handler { private static final int CHECK_CONNECTION_EXPIRATION = 1; private static final int ATTENTION_CHECK_TIMEOUT = 2; @@ -596,7 +593,8 @@ public class AttentionManagerService extends SystemService { } } - private void cancel(UserState userState) { + @VisibleForTesting + void cancel(UserState userState) { if (userState == null || userState.mCurrentAttentionCheck == null) { return; } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index b7746477f0f8..44c1715cfed5 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -406,6 +406,10 @@ import java.util.ArrayList; mAudioService.checkVolumeCecOnHdmiConnection(state, caller); } + /*package*/ boolean hasAudioFocusUsers() { + return mAudioService.hasAudioFocusUsers(); + } + //--------------------------------------------------------------------- // Message handling on behalf of helper classes /*package*/ void postBroadcastScoConnectionState(int state) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 7750bfefae05..91b51b4989d8 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -819,11 +819,12 @@ public final class AudioDeviceInventory { if (((device == musicDevice) || mDeviceBroker.isInCommunication()) && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy() && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) { - if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)) { + if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/) + && !mDeviceBroker.hasAudioFocusUsers()) { // no media playback, not a "becoming noisy" situation, otherwise it could cause // the pausing of some apps that are playing remotely AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( - "dropping ACTION_AUDIO_BECOMING_NOISY, no media playback")).printLog(TAG)); + "dropping ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG)); return 0; } mDeviceBroker.postBroadcastBecomingNoisy(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 77472ed288c3..aee08bb09401 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1523,9 +1523,11 @@ public class AudioService extends IAudioService.Stub + ", flags=" + flags + ", caller=" + caller + ", volControlStream=" + mVolumeControlStream + ", userSelect=" + mUserSelectedVolumeControlStream); - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType, - direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) - .append("/").append(caller).append(" uid:").append(uid).toString())); + if (direction != AudioManager.ADJUST_SAME) { + sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType, + direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) + .append("/").append(caller).append(" uid:").append(uid).toString())); + } final int streamType; synchronized (mForceControlStreamLock) { // Request lock in case mVolumeControlStream is changed by other thread. @@ -5578,6 +5580,10 @@ public class AudioService extends IAudioService.Stub return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr); } + /*package*/ boolean hasAudioFocusUsers() { + return mMediaFocusControl.hasAudioFocusUsers(); + } + //========================================================================================== private boolean readCameraSoundForced() { return SystemProperties.getBoolean("audio.camerasound.force", false) || @@ -6320,6 +6326,11 @@ public class AudioService extends IAudioService.Stub @Override public void adjustStreamVolumeForUid(int streamType, int direction, int flags, String callingPackage, int uid) { + if (direction != AudioManager.ADJUST_SAME) { + sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_VOL_UID, streamType, + direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) + .append(" uid:").append(uid).toString())); + } adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid); } @@ -6660,6 +6671,13 @@ public class AudioService extends IAudioService.Stub return AudioManager.SUCCESS; } + /** see AudioManager.hasRegisteredDynamicPolicy */ + public boolean hasRegisteredDynamicPolicy() { + synchronized (mAudioPolicies) { + return !mAudioPolicies.isEmpty(); + } + } + private final Object mExtVolumeControllerLock = new Object(); private IAudioPolicyCallback mExtVolumeController; private void setExtVolumeController(IAudioPolicyCallback apc) { diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java index 7ccb45e97912..d999217bf29b 100644 --- a/services/core/java/com/android/server/audio/AudioServiceEvents.java +++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java @@ -94,6 +94,7 @@ public class AudioServiceEvents { static final int VOL_SET_STREAM_VOL = 2; static final int VOL_SET_HEARING_AID_VOL = 3; static final int VOL_SET_AVRCP_VOL = 4; + static final int VOL_ADJUST_VOL_UID = 5; final int mOp; final int mStream; @@ -160,6 +161,13 @@ public class AudioServiceEvents { return new StringBuilder("setAvrcpVolume:") .append(" index:").append(mVal1) .toString(); + case VOL_ADJUST_VOL_UID: + return new StringBuilder("adjustStreamVolumeForUid(stream:") + .append(AudioSystem.streamToString(mStream)) + .append(" dir:").append(AudioManager.adjustToString(mVal1)) + .append(" flags:0x").append(Integer.toHexString(mVal2)) + .append(") from ").append(mCaller) + .toString(); default: return new StringBuilder("FIXME invalid op:").append(mOp).toString(); } } diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index 1e58b454a15b..5c93071fd551 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -162,6 +162,12 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } + /*package*/ boolean hasAudioFocusUsers() { + synchronized (mAudioFocusLock) { + return !mFocusStack.empty(); + } + } + /** * Discard the current audio focus owner. * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index b2c5c053528e..91da7af44f0a 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -134,7 +134,8 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", Owner: " + getOwnerString() + ", isBP: " + isBiometricPrompt() + ", listener: " + listener - + ", requireConfirmation: " + mRequireConfirmation); + + ", requireConfirmation: " + mRequireConfirmation + + ", user: " + getTargetUserId()); if (authenticated) { mAlreadyDone = true; diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java index fe0fc91a4b27..e218c6b399a2 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -548,7 +548,8 @@ public class FaceService extends BiometricServiceBase { throws RemoteException { if (mFaceServiceReceiver != null) { if (biometric == null || biometric instanceof Face) { - mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face)biometric); + mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric, + userId); } else { Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric"); } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 258c325716f2..d28482ef82ab 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -52,6 +52,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; +import android.view.autofill.AutofillManagerInternal; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -159,6 +160,7 @@ public class ClipboardService extends SystemService { private final PackageManager mPm; private final AppOpsManager mAppOps; private final ContentCaptureManagerInternal mContentCaptureInternal; + private final AutofillManagerInternal mAutofillInternal; private final IBinder mPermissionOwner; private HostClipboardMonitor mHostClipboardMonitor = null; private Thread mHostMonitorThread = null; @@ -179,6 +181,7 @@ public class ClipboardService extends SystemService { mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mContentCaptureInternal = LocalServices.getService(ContentCaptureManagerInternal.class); + mAutofillInternal = LocalServices.getService(AutofillManagerInternal.class); final IBinder permOwner = mUgmInternal.newUriPermissionOwner("clipboard"); mPermissionOwner = permOwner; if (IS_EMULATOR) { @@ -653,13 +656,18 @@ public class ClipboardService extends SystemService { // Clipboard can only be read by applications with focus.. boolean allowed = mWm.isUidFocused(callingUid); if (!allowed && mContentCaptureInternal != null) { - // ...or the Intelligence Service + // ...or the Content Capture Service allowed = mContentCaptureInternal.isContentCaptureServiceForUser(callingUid, userId); } + if (!allowed && mAutofillInternal != null) { + // ...or the Augmented Autofill Service + allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(callingUid, + userId); + } if (!allowed) { Slog.e(TAG, "Denying clipboard access to " + callingPackage - + ", application is not in focus neither is the IntelligeService for " + + ", application is not in focus neither is a system service for " + "user " + userId); } return allowed; diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java index 948c690956d3..a1a8e355dcec 100644 --- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java +++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java @@ -33,6 +33,7 @@ import android.text.TextUtils; import android.util.Pair; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.TrafficStatsConstants; import libcore.io.IoUtils; @@ -381,7 +382,8 @@ public class NetworkDiagnostics { protected void setupSocket( int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort) throws ErrnoException, IOException { - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_PROBE); try { mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol); } finally { diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java index 1ac09ad462a1..f6ce2dc68b99 100644 --- a/services/core/java/com/android/server/connectivity/PacManager.java +++ b/services/core/java/com/android/server/connectivity/PacManager.java @@ -39,6 +39,7 @@ import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.TrafficStatsConstants; import com.android.net.IProxyCallback; import com.android.net.IProxyPortListener; import com.android.net.IProxyService; @@ -111,7 +112,8 @@ public class PacManager { String file; final Uri pacUrl = mPacUrl; if (Uri.EMPTY.equals(pacUrl)) return; - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PAC); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_PAC); try { file = get(pacUrl); } catch (IOException ioe) { diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index cec4d693ad32..75b9705e1045 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -523,11 +523,17 @@ public class InputManagerService extends IInputManager.Stub } - InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); - InputMonitorHost host = new InputMonitorHost(inputChannels[0]); - inputChannels[0].setToken(host.asBinder()); - nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, true /*isGestureMonitor*/); - return new InputMonitor(inputChannelName, inputChannels[1], host); + final long ident = Binder.clearCallingIdentity(); + try { + InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); + InputMonitorHost host = new InputMonitorHost(inputChannels[0]); + inputChannels[0].setToken(host.asBinder()); + nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, + true /*isGestureMonitor*/); + return new InputMonitor(inputChannelName, inputChannels[1], host); + } finally { + Binder.restoreCallingIdentity(ident); + } } /** diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index e88d62f58507..3c97c39f70a0 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -4710,10 +4710,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @ShellCommandResult private int handleShellCommandEnableDisableInputMethod( @NonNull ShellCommand shellCommand, boolean enabled) { + final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); final String imeId = shellCommand.getNextArgRequired(); final PrintWriter out = shellCommand.getOutPrintWriter(); final PrintWriter error = shellCommand.getErrPrintWriter(); - final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); synchronized (mMethodMap) { final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved, mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter()); @@ -4733,6 +4733,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * * <p>You cannot use this helper method if the command has other options.</p> * + * <p>CAVEAT: This method must be called only once before any other + * {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the + * main arguments.</p> + * * @param shellCommand {@link ShellCommand} from which options should be obtained. * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified. */ @@ -4819,10 +4823,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @ShellCommandResult private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) { + final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); final String imeId = shellCommand.getNextArgRequired(); final PrintWriter out = shellCommand.getOutPrintWriter(); final PrintWriter error = shellCommand.getErrPrintWriter(); - final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); synchronized (mMethodMap) { final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved, mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter()); @@ -4864,7 +4868,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub out.print("Input method "); out.print(imeId); out.print(" selected for user #"); - error.println(userId); + out.println(userId); } } } diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index a2515c8bb8cc..580150ed887e 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -1228,6 +1228,24 @@ public final class MultiClientInputMethodManagerService { public boolean isUidAllowedOnDisplay(int displayId, int uid) { return mIWindowManagerInternal.isUidAllowedOnDisplay(displayId, uid); } + + @BinderThread + @Override + public void setActive(int clientId, boolean active) { + synchronized (mPerUserData.mLock) { + final InputMethodClientInfo clientInfo = + mPerUserData.getClientFromIdLocked(clientId); + if (clientInfo == null) { + Slog.e(TAG, "Unknown clientId=" + clientId); + return; + } + try { + clientInfo.mClient.setActive(active, false /* fullscreen */); + } catch (RemoteException e) { + return; + } + } + } } /** diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index e28f89c59018..96fc6ec5907c 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -495,6 +495,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements @Override public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) { mHandler.post(() -> mGnssConfiguration.setSatelliteBlacklist(constellations, svids)); + mGnssMetrics.resetConstellationTypes(); } private void subscriptionOrCarrierConfigChanged(Context context) { @@ -1443,6 +1444,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0 ? "" : "F")); } + + if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) { + int constellationType = + (info.mSvidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH) + & GnssStatus.CONSTELLATION_TYPE_MASK; + mGnssMetrics.logConstellationType(constellationType); + } } if (usedInFixCount > 0) { meanCn0 /= usedInFixCount; diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java index c012ee41b29b..7dffcb4c32a9 100644 --- a/services/core/java/com/android/server/location/GpsXtraDownloader.java +++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java @@ -20,6 +20,8 @@ import android.net.TrafficStats; import android.text.TextUtils; import android.util.Log; +import com.android.internal.util.TrafficStatsConstants; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -92,7 +94,8 @@ public class GpsXtraDownloader { // load balance our requests among the available servers while (result == null) { - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_GPS); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_GPS); try { result = doDownload(mXtraServers[mNextServerIndex]); } finally { diff --git a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java index 686ae2bbaede..5cbd237a0722 100644 --- a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java +++ b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java @@ -52,10 +52,12 @@ public class PasswordSlotManager { // This maps each used password slot to the OS image that created it. Password slots are // integer keys/indices into secure storage. The OS image is recorded as a string. The factory // image is "host" and GSIs are "gsi<N>" where N >= 1. - private final Map<Integer, String> mSlotMap; + private Map<Integer, String> mSlotMap; + + // Cache the active slots until loadSlotMap() is called. + private Set<Integer> mActiveSlots; public PasswordSlotManager() { - mSlotMap = loadSlotMap(); } @VisibleForTesting @@ -74,6 +76,11 @@ public class PasswordSlotManager { * @throws RuntimeException */ public void refreshActiveSlots(Set<Integer> activeSlots) throws RuntimeException { + if (mSlotMap == null) { + mActiveSlots = new HashSet<Integer>(activeSlots); + return; + } + // Update which slots are owned by the current image. final HashSet<Integer> slotsToDelete = new HashSet<Integer>(); for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) { @@ -100,6 +107,7 @@ public class PasswordSlotManager { * @throws RuntimeException */ public void markSlotInUse(int slot) throws RuntimeException { + ensureSlotMapLoaded(); if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) { throw new RuntimeException("password slot " + slot + " is not available"); } @@ -113,6 +121,7 @@ public class PasswordSlotManager { * @throws RuntimeException */ public void markSlotDeleted(int slot) throws RuntimeException { + ensureSlotMapLoaded(); if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) { throw new RuntimeException("password slot " + slot + " cannot be deleted"); } @@ -126,6 +135,7 @@ public class PasswordSlotManager { * @return Integer set of all used slots. */ public Set<Integer> getUsedSlots() { + ensureSlotMapLoaded(); return Collections.unmodifiableSet(mSlotMap.keySet()); } @@ -167,8 +177,21 @@ public class PasswordSlotManager { return new HashMap<Integer, String>(); } + private void ensureSlotMapLoaded() { + if (mSlotMap == null) { + mSlotMap = loadSlotMap(); + if (mActiveSlots != null) { + refreshActiveSlots(mActiveSlots); + mActiveSlots = null; + } + } + } + @VisibleForTesting protected void saveSlotMap(OutputStream stream) throws IOException { + if (mSlotMap == null) { + return; + } final Properties props = new Properties(); for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) { props.setProperty(entry.getKey().toString(), entry.getValue()); @@ -177,6 +200,9 @@ public class PasswordSlotManager { } private void saveSlotMap() { + if (mSlotMap == null) { + return; + } if (!getSlotMapFile().getParentFile().exists()) { Slog.w(TAG, "Not saving slot map, " + getSlotMapDir() + " does not exist"); return; diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java index 603d7cfb4525..eb706d7791d3 100644 --- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java +++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java @@ -142,7 +142,8 @@ class AudioPlayerStateMonitor { /** * Returns the sorted list of UIDs that have had active audio playback. (i.e. playing an - * audio/video) The UID whose audio playback becomes active at the last comes first. + * audio/video) The UID whose audio is currently playing comes first, then the UID whose audio + * playback becomes active at the last comes next. */ public IntArray getSortedAudioPlaybackClientUids() { IntArray sortedAudioPlaybackClientUids = new IntArray(); @@ -253,6 +254,26 @@ class AudioPlayerStateMonitor { mSortedAudioPlaybackClientUids.add(0, uid); } } + + if (mActiveAudioUids.size() > 0 + && !mActiveAudioUids.contains(mSortedAudioPlaybackClientUids.get(0))) { + int firstActiveUid = -1; + int firatActiveUidIndex = -1; + for (int i = 1; i < mSortedAudioPlaybackClientUids.size(); ++i) { + int uid = mSortedAudioPlaybackClientUids.get(i); + if (mActiveAudioUids.contains(uid)) { + firatActiveUidIndex = i; + firstActiveUid = uid; + break; + } + } + for (int i = firatActiveUidIndex; i > 0; --i) { + mSortedAudioPlaybackClientUids.set(i, + mSortedAudioPlaybackClientUids.get(i - 1)); + } + mSortedAudioPlaybackClientUids.set(0, firstActiveUid); + } + // Notify the active state change of audio players. for (AudioPlaybackConfiguration config : configs) { final int pii = config.getPlayerInterfaceId(); diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java deleted file mode 100644 index d284c6091f73..000000000000 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.media; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.media.IMediaRoute2Callback; -import android.media.IMediaRoute2Provider; -import android.media.MediaRoute2ProviderService; -import android.os.Handler; -import android.os.IBinder; -import android.os.IBinder.DeathRecipient; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.Log; -import android.util.Slog; - -import java.io.PrintWriter; -import java.lang.ref.WeakReference; - -/** - * Maintains a connection to a particular media route provider service. - */ -final class MediaRoute2ProviderProxy implements ServiceConnection { - private static final String TAG = "MediaRoute2ProviderProxy"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final Context mContext; - private final ComponentName mComponentName; - private final int mUserId; - private final Handler mHandler; - - private Callback mCallback; - - // Selected Route info - public int mSelectedUid; - public String mSelectedRouteId; - - // Connection state - private boolean mRunning; - private boolean mBound; - private Connection mActiveConnection; - private boolean mConnectionReady; - - MediaRoute2ProviderProxy(Context context, ComponentName componentName, int userId) { - mContext = context; - mComponentName = componentName; - mUserId = userId; - mHandler = new Handler(); - } - - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "Proxy"); - pw.println(prefix + " mUserId=" + mUserId); - pw.println(prefix + " mRunning=" + mRunning); - pw.println(prefix + " mBound=" + mBound); - pw.println(prefix + " mActiveConnection=" + mActiveConnection); - pw.println(prefix + " mConnectionReady=" + mConnectionReady); - } - - public void setCallback(Callback callback) { - mCallback = callback; - } - - public void setSelectedRoute(int uid, String routeId) { - if (mConnectionReady) { - mActiveConnection.selectRoute(uid, routeId); - updateBinding(); - } - } - - public boolean hasComponentName(String packageName, String className) { - return mComponentName.getPackageName().equals(packageName) - && mComponentName.getClassName().equals(className); - } - - public String getFlattenedComponentName() { - return mComponentName.flattenToShortString(); - } - - public void start() { - if (!mRunning) { - if (DEBUG) { - Slog.d(TAG, this + ": Starting"); - } - - mRunning = true; - updateBinding(); - } - } - - public void stop() { - if (mRunning) { - if (DEBUG) { - Slog.d(TAG, this + ": Stopping"); - } - - mRunning = false; - updateBinding(); - } - } - - public void rebindIfDisconnected() { - if (mActiveConnection == null && shouldBind()) { - unbind(); - bind(); - } - } - - private void updateBinding() { - if (shouldBind()) { - bind(); - } else { - unbind(); - } - } - - private boolean shouldBind() { - //TODO: binding could be delayed until it's necessary. - if (mRunning) { - return true; - } - return false; - } - - private void bind() { - if (!mBound) { - if (DEBUG) { - Slog.d(TAG, this + ": Binding"); - } - - Intent service = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE); - service.setComponent(mComponentName); - try { - mBound = mContext.bindServiceAsUser(service, this, - Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, - new UserHandle(mUserId)); - if (!mBound && DEBUG) { - Slog.d(TAG, this + ": Bind failed"); - } - } catch (SecurityException ex) { - if (DEBUG) { - Slog.d(TAG, this + ": Bind failed", ex); - } - } - } - } - - private void unbind() { - if (mBound) { - if (DEBUG) { - Slog.d(TAG, this + ": Unbinding"); - } - - mBound = false; - disconnect(); - mContext.unbindService(this); - } - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (DEBUG) { - Slog.d(TAG, this + ": Connected"); - } - - if (mBound) { - disconnect(); - - IMediaRoute2Provider provider = IMediaRoute2Provider.Stub.asInterface(service); - if (provider != null) { - Connection connection = new Connection(provider); - if (connection.register()) { - mActiveConnection = connection; - } else { - if (DEBUG) { - Slog.d(TAG, this + ": Registration failed"); - } - } - } else { - Slog.e(TAG, this + ": Service returned invalid remote display provider binder"); - } - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - if (DEBUG) { - Slog.d(TAG, this + ": Service disconnected"); - } - disconnect(); - } - - private void onConnectionReady(Connection connection) { - if (mActiveConnection == connection) { - mConnectionReady = true; - } - } - - private void onConnectionDied(Connection connection) { - if (mActiveConnection == connection) { - if (DEBUG) { - Slog.d(TAG, this + ": Service connection died"); - } - disconnect(); - } - } - - private void onRouteSelected(Connection connection, int uid, String routeId) { - mSelectedUid = uid; - mSelectedRouteId = routeId; - - if (mActiveConnection == connection) { - if (DEBUG) { - Slog.d(TAG, this + ": State changed "); - } - mHandler.post(mStateChanged); - } - } - - private void disconnect() { - if (mActiveConnection != null) { - mConnectionReady = false; - mActiveConnection.dispose(); - mActiveConnection = null; - } - } - - @Override - public String toString() { - return "Service connection " + mComponentName.flattenToShortString(); - } - - private final Runnable mStateChanged = new Runnable() { - @Override - public void run() { - if (mCallback != null) { - mCallback.onProviderStateChanged(MediaRoute2ProviderProxy.this); - } - } - }; - - public interface Callback { - void onProviderStateChanged(MediaRoute2ProviderProxy provider); - } - - private final class Connection implements DeathRecipient { - private final IMediaRoute2Provider mProvider; - private final ProviderCallback mCallback; - - Connection(IMediaRoute2Provider provider) { - mProvider = provider; - mCallback = new ProviderCallback(this); - } - - public boolean register() { - try { - mProvider.asBinder().linkToDeath(this, 0); - mProvider.setCallback(mCallback); - mHandler.post(new Runnable() { - @Override - public void run() { - onConnectionReady(Connection.this); - } - }); - return true; - } catch (RemoteException ex) { - binderDied(); - } - return false; - } - - public void dispose() { - mProvider.asBinder().unlinkToDeath(this, 0); - mCallback.dispose(); - } - - public void selectRoute(int uid, String id) { - try { - mProvider.selectRoute(uid, id); - } catch (RemoteException ex) { - Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex); - } - } - - @Override - public void binderDied() { - mHandler.post(new Runnable() { - @Override - public void run() { - onConnectionDied(Connection.this); - } - }); - } - - void postRouteSelected(int uid, String routeId) { - mHandler.post(new Runnable() { - @Override - public void run() { - onRouteSelected(Connection.this, uid, routeId); - } - }); - } - } - - private static final class ProviderCallback extends IMediaRoute2Callback.Stub { - private final WeakReference<Connection> mConnectionRef; - - ProviderCallback(Connection connection) { - mConnectionRef = new WeakReference<Connection>(connection); - } - - public void dispose() { - mConnectionRef.clear(); - } - - @Override - public void onRouteSelected(int uid, String routeId) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.postRouteSelected(uid, routeId); - } - } - } -} diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java deleted file mode 100644 index 08d8c58f6f87..000000000000 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.media; - -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.media.MediaRoute2ProviderService; -import android.os.Handler; -import android.os.UserHandle; -import android.util.Log; -import android.util.Slog; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; - -/** - */ -final class MediaRoute2ProviderWatcher { - private static final String TAG = "MediaRouteProvider"; // max. 23 chars - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final Context mContext; - private final Callback mCallback; - private final Handler mHandler; - private final int mUserId; - private final PackageManager mPackageManager; - - private final ArrayList<MediaRoute2ProviderProxy> mProviders = new ArrayList<>(); - private boolean mRunning; - - MediaRoute2ProviderWatcher(Context context, - Callback callback, Handler handler, int userId) { - mContext = context; - mCallback = callback; - mHandler = handler; - mUserId = userId; - mPackageManager = context.getPackageManager(); - } - - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "Watcher"); - pw.println(prefix + " mUserId=" + mUserId); - pw.println(prefix + " mRunning=" + mRunning); - pw.println(prefix + " mProviders.size()=" + mProviders.size()); - } - - public void start() { - if (!mRunning) { - mRunning = true; - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_CHANGED); - filter.addAction(Intent.ACTION_PACKAGE_REPLACED); - filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); - filter.addDataScheme("package"); - mContext.registerReceiverAsUser(mScanPackagesReceiver, - new UserHandle(mUserId), filter, null, mHandler); - - // Scan packages. - // Also has the side-effect of restarting providers if needed. - mHandler.post(mScanPackagesRunnable); - } - } - - public void stop() { - if (mRunning) { - mRunning = false; - - mContext.unregisterReceiver(mScanPackagesReceiver); - mHandler.removeCallbacks(mScanPackagesRunnable); - - // Stop all providers. - for (int i = mProviders.size() - 1; i >= 0; i--) { - mProviders.get(i).stop(); - } - } - } - - private void scanPackages() { - if (!mRunning) { - return; - } - - // Add providers for all new services. - // Reorder the list so that providers left at the end will be the ones to remove. - int targetIndex = 0; - Intent intent = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE); - for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser( - intent, 0, mUserId)) { - ServiceInfo serviceInfo = resolveInfo.serviceInfo; - if (serviceInfo != null) { - int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name); - if (sourceIndex < 0) { - MediaRoute2ProviderProxy provider = - new MediaRoute2ProviderProxy(mContext, - new ComponentName(serviceInfo.packageName, serviceInfo.name), - mUserId); - provider.start(); - mProviders.add(targetIndex++, provider); - mCallback.addProvider(provider); - } else if (sourceIndex >= targetIndex) { - MediaRoute2ProviderProxy provider = mProviders.get(sourceIndex); - provider.start(); // restart the provider if needed - provider.rebindIfDisconnected(); - Collections.swap(mProviders, sourceIndex, targetIndex++); - } - } - } - - // Remove providers for missing services. - if (targetIndex < mProviders.size()) { - for (int i = mProviders.size() - 1; i >= targetIndex; i--) { - MediaRoute2ProviderProxy provider = mProviders.get(i); - mCallback.removeProvider(provider); - mProviders.remove(provider); - provider.stop(); - } - } - } - - private int findProvider(String packageName, String className) { - int count = mProviders.size(); - for (int i = 0; i < count; i++) { - MediaRoute2ProviderProxy provider = mProviders.get(i); - if (provider.hasComponentName(packageName, className)) { - return i; - } - } - return -1; - } - - private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (DEBUG) { - Slog.d(TAG, "Received package manager broadcast: " + intent); - } - scanPackages(); - } - }; - - private final Runnable mScanPackagesRunnable = new Runnable() { - @Override - public void run() { - scanPackages(); - } - }; - - public interface Callback { - void addProvider(MediaRoute2ProviderProxy provider); - void removeProvider(MediaRoute2ProviderProxy provider); - } -} diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index a43533f35cd9..23d3ce063a3e 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -30,7 +30,6 @@ import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; import android.media.IAudioService; -import android.media.IMediaRouter2ManagerClient; import android.media.IMediaRouterClient; import android.media.IMediaRouterService; import android.media.MediaRouter; @@ -50,7 +49,6 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.IntArray; import android.util.Log; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -98,7 +96,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final Object mLock = new Object(); private final SparseArray<UserRecord> mUserRecords = new SparseArray<>(); private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>(); - private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>(); private int mCurrentUserId = -1; private final IAudioService mAudioService; private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; @@ -307,22 +304,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override - public void setControlCategories(IMediaRouterClient client, List<String> categories) { - if (client == null) { - throw new IllegalArgumentException("client must not be null"); - } - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - setControlCategoriesLocked(client, categories); - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - - // Binder call - @Override public void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan) { if (client == null) { @@ -421,65 +402,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } - // Binder call - @Override - public void registerManagerAsUser(IMediaRouter2ManagerClient client, - String packageName, int userId) { - if (client == null) { - throw new IllegalArgumentException("client must not be null"); - } - //TODO: should check permission - final boolean trusted = true; - - final int uid = Binder.getCallingUid(); - if (!validatePackageName(uid, packageName)) { - throw new SecurityException("packageName must match the calling uid"); - } - - final int pid = Binder.getCallingPid(); - final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, - false /*allowAll*/, true /*requireFull*/, "registerManagerAsUser", packageName); - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - registerManagerLocked(client, uid, pid, packageName, resolvedUserId, trusted); - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - - // Binder call - @Override - public void unregisterManager(IMediaRouter2ManagerClient client) { - if (client == null) { - throw new IllegalArgumentException("client must not be null"); - } - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - unregisterManagerLocked(client, false); - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - - // Binder call - @Override - public void setRemoteRoute(IMediaRouter2ManagerClient client, - int uid, String routeId, boolean explicit) { - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - setRemoteRouteLocked(client, uid, routeId, explicit); - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - void restoreBluetoothA2dp() { try { boolean a2dpOn; @@ -551,12 +473,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } - void clientDied(ManagerRecord managerRecord) { - synchronized (mLock) { - unregisterManagerLocked(managerRecord.mClient, true); - } - } - private void registerClientLocked(IMediaRouterClient client, int uid, int pid, String packageName, int userId, boolean trusted) { final IBinder binder = client.asBinder(); @@ -604,17 +520,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub return null; } - private void setControlCategoriesLocked(IMediaRouterClient client, List<String> categories) { - final IBinder binder = client.asBinder(); - ClientRecord clientRecord = mAllClientRecords.get(binder); - - if (clientRecord != null) { - clientRecord.mControlCategories = categories; - clientRecord.mUserRecord.mHandler.obtainMessage( - UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget(); - } - } - private void setDiscoveryRequestLocked(IMediaRouterClient client, int routeTypes, boolean activeScan) { final IBinder binder = client.asBinder(); @@ -668,63 +573,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } - private void registerManagerLocked(IMediaRouter2ManagerClient client, - int uid, int pid, String packageName, int userId, boolean trusted) { - final IBinder binder = client.asBinder(); - ManagerRecord managerRecord = mAllManagerRecords.get(binder); - if (managerRecord == null) { - boolean newUser = false; - UserRecord userRecord = mUserRecords.get(userId); - if (userRecord == null) { - userRecord = new UserRecord(userId); - newUser = true; - } - managerRecord = new ManagerRecord(userRecord, client, uid, pid, packageName, trusted); - try { - binder.linkToDeath(managerRecord, 0); - } catch (RemoteException ex) { - throw new RuntimeException("Media router client died prematurely.", ex); - } - - if (newUser) { - mUserRecords.put(userId, userRecord); - initializeUserLocked(userRecord); - } - - userRecord.mManagerRecords.add(managerRecord); - mAllManagerRecords.put(binder, managerRecord); - - // send client usage to manager - final int clientCount = userRecord.mClientRecords.size(); - for (int i = 0; i < clientCount; i++) { - userRecord.mHandler.obtainMessage(UserHandler.MSG_UPDATE_CLIENT_USAGE, - userRecord.mClientRecords.get(i)).sendToTarget(); - } - } - } - - private void unregisterManagerLocked(IMediaRouter2ManagerClient client, boolean died) { - ManagerRecord clientRecord = mAllManagerRecords.remove(client.asBinder()); - if (clientRecord != null) { - UserRecord userRecord = clientRecord.mUserRecord; - userRecord.mManagerRecords.remove(clientRecord); - clientRecord.dispose(); - disposeUserIfNeededLocked(userRecord); // since client removed from user - } - } - - private void setRemoteRouteLocked(IMediaRouter2ManagerClient client, - int uid, String routeId, boolean explicit) { - ManagerRecord managerRecord = mAllManagerRecords.get(client.asBinder()); - if (managerRecord != null) { - if (explicit && managerRecord.mTrusted) { - Pair<Integer, String> obj = new Pair<>(uid, routeId); - managerRecord.mUserRecord.mHandler.obtainMessage( - UserHandler.MSG_SELECT_REMOTE_ROUTE, obj).sendToTarget(); - } - } - } - private void requestSetVolumeLocked(IMediaRouterClient client, String routeId, int volume) { final IBinder binder = client.asBinder(); @@ -817,46 +665,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } - final class ManagerRecord implements DeathRecipient { - public final UserRecord mUserRecord; - public final IMediaRouter2ManagerClient mClient; - public final int mUid; - public final int mPid; - public final String mPackageName; - public final boolean mTrusted; - - ManagerRecord(UserRecord userRecord, IMediaRouter2ManagerClient client, - int uid, int pid, String packageName, boolean trusted) { - mUserRecord = userRecord; - mClient = client; - mUid = uid; - mPid = pid; - mPackageName = packageName; - mTrusted = trusted; - } - - public void dispose() { - mClient.asBinder().unlinkToDeath(this, 0); - } - - @Override - public void binderDied() { - clientDied(this); - } - - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - - final String indent = prefix + " "; - pw.println(indent + "mTrusted=" + mTrusted); - } - - @Override - public String toString() { - return "Client " + mPackageName + " (pid " + mPid + ")"; - } - } - /** * Information about a particular client of the media router. * The contents of this object is guarded by mLock. @@ -868,7 +676,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub public final int mPid; public final String mPackageName; public final boolean mTrusted; - public List<String> mControlCategories; public int mRouteTypes; public boolean mActiveScan; @@ -919,8 +726,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub */ final class UserRecord { public final int mUserId; - public final ArrayList<ClientRecord> mClientRecords = new ArrayList<>(); - public final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>(); + public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>(); public final UserHandler mHandler; public MediaRouterClientState mRouterState; @@ -975,9 +781,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub */ static final class UserHandler extends Handler implements RemoteDisplayProviderWatcher.Callback, - RemoteDisplayProviderProxy.Callback, - MediaRoute2ProviderWatcher.Callback, - MediaRoute2ProviderProxy.Callback { + RemoteDisplayProviderProxy.Callback { public static final int MSG_START = 1; public static final int MSG_STOP = 2; public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3; @@ -988,9 +792,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub private static final int MSG_UPDATE_CLIENT_STATE = 8; private static final int MSG_CONNECTION_TIMED_OUT = 9; - private static final int MSG_SELECT_REMOTE_ROUTE = 10; - private static final int MSG_UPDATE_CLIENT_USAGE = 11; - private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1; private static final int TIMEOUT_REASON_CONNECTION_LOST = 2; private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 3; @@ -1006,17 +807,11 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final MediaRouterService mService; private final UserRecord mUserRecord; private final RemoteDisplayProviderWatcher mWatcher; - private final MediaRoute2ProviderWatcher mMediaWatcher; - private final ArrayList<ProviderRecord> mProviderRecords = new ArrayList<ProviderRecord>(); private final ArrayList<IMediaRouterClient> mTempClients = new ArrayList<IMediaRouterClient>(); - private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders = - new ArrayList<>(); - private final ArrayList<IMediaRouter2ManagerClient> mTempManagers = new ArrayList<>(); - private boolean mRunning; private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE; private RouteRecord mSelectedRouteRecord; @@ -1031,8 +826,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub mUserRecord = userRecord; mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this, this, mUserRecord.mUserId); - mMediaWatcher = new MediaRoute2ProviderWatcher(service.mContext, this, - this, mUserRecord.mUserId); } @Override @@ -1074,15 +867,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub connectionTimedOut(); break; } - case MSG_SELECT_REMOTE_ROUTE: { - Pair<Integer, String> obj = (Pair<Integer, String>) msg.obj; - selectRemoteRoute(obj.first, obj.second); - break; - } - case MSG_UPDATE_CLIENT_USAGE: { - updateClientUsage((ClientRecord) msg.obj); - break; - } } } @@ -1114,7 +898,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub if (!mRunning) { mRunning = true; mWatcher.start(); // also starts all providers - mMediaWatcher.start(); } } @@ -1123,7 +906,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub mRunning = false; unselectSelectedRoute(); mWatcher.stop(); // also stops all providers - mMediaWatcher.stop(); } } @@ -1255,26 +1037,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } - @Override - public void addProvider(MediaRoute2ProviderProxy provider) { - provider.setCallback(this); - mMediaProviders.add(provider); - } - - @Override - public void removeProvider(MediaRoute2ProviderProxy provider) { - mMediaProviders.remove(provider); - } - - @Override - public void onProviderStateChanged(MediaRoute2ProviderProxy provider) { - updateProvider(provider); - } - - private void updateProvider(MediaRoute2ProviderProxy provider) { - scheduleUpdateClientState(); - } - /** * This function is called whenever the state of the selected route may have changed. * It checks the state and updates timeouts or unselects the route as appropriate. @@ -1385,17 +1147,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub unselectSelectedRoute(); } - private void selectRemoteRoute(int uid, String routeId) { - if (routeId != null) { - final int providerCount = mMediaProviders.size(); - - //TODO: should find proper provider (currently assumes a single provider) - for (int i = 0; i < providerCount; ++i) { - mMediaProviders.get(i).setSelectedRoute(uid, routeId); - } - } - } - private void scheduleUpdateClientState() { if (!mClientStateUpdateScheduled) { mClientStateUpdateScheduled = true; @@ -1413,15 +1164,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub mProviderRecords.get(i).appendClientState(routerState); } - //TODO: send provider info - int selectedUid = 0; - String selectedRouteId = null; - final int mediaCount = mMediaProviders.size(); - for (int i = 0; i < mediaCount; i++) { - selectedUid = mMediaProviders.get(i).mSelectedUid; - selectedRouteId = mMediaProviders.get(i).mSelectedRouteId; - } - try { synchronized (mService.mLock) { // Update the UserRecord. @@ -1432,11 +1174,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub for (int i = 0; i < count; i++) { mTempClients.add(mUserRecord.mClientRecords.get(i).mClient); } - - final int count2 = mUserRecord.mManagerRecords.size(); - for (int i = 0; i < count2; i++) { - mTempManagers.add(mUserRecord.mManagerRecords.get(i).mClient); - } } // Notify all clients (outside of the lock). @@ -1448,39 +1185,9 @@ public final class MediaRouterService extends IMediaRouterService.Stub Slog.w(TAG, "Failed to call onStateChanged. Client probably died."); } } - //TODO: Call proper callbacks when provider descriptor is implemented. - final int count2 = mTempManagers.size(); - for (int i = 0; i < count2; i++) { - try { - mTempManagers.get(i).onRouteSelected(selectedUid, selectedRouteId); - } catch (RemoteException ex) { - Slog.w(TAG, "Failed to call onStateChanged. Manager probably died.", ex); - } - } } finally { // Clear the list in preparation for the next time. mTempClients.clear(); - mTempManagers.clear(); - } - } - - private void updateClientUsage(ClientRecord clientRecord) { - List<IMediaRouter2ManagerClient> managers = new ArrayList<>(); - synchronized (mService.mLock) { - final int count = mUserRecord.mManagerRecords.size(); - for (int i = 0; i < count; i++) { - managers.add(mUserRecord.mManagerRecords.get(i).mClient); - } - } - final int count = managers.size(); - for (int i = 0; i < count; i++) { - try { - managers.get(i).onControlCategoriesChanged(clientRecord.mUid, - clientRecord.mControlCategories); - } catch (RemoteException ex) { - Slog.w(TAG, "Failed to call onControlCategoriesChanged. " - + "Manager probably died.", ex); - } } } @@ -1867,5 +1574,4 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } } - } diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java index de36deafa4d7..a5f22175331d 100644 --- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java @@ -171,7 +171,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(mContext); mAudioPlayerStateMonitor.registerListener( (config, isRemoved) -> { - if (isRemoved || !config.isActive() || config.getPlayerType() + if (config.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) { return; } @@ -1037,8 +1037,9 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { // it's closed. // TODO: Keep controller as well for better readability // because the GC behavior isn't straightforward. - MediaController2 controller = new MediaController2(mContext, sessionToken, - new HandlerExecutor(mHandler), callback); + MediaController2 controller = new MediaController2.Builder(mContext, sessionToken) + .setControllerCallback(new HandlerExecutor(mHandler), callback) + .build(); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index ec53e98ec547..3a84b1e18e36 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -452,10 +452,7 @@ final class OverlayManagerServiceImpl { final OverlayInfo overlayInfo = mSettings.getOverlayInfo(packageName, userId); if (mSettings.remove(packageName, userId)) { removeIdmapIfPossible(overlayInfo); - if (overlayInfo.isEnabled()) { - // Only trigger updates if the overlay was enabled. - mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId); - } + mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId); } } catch (OverlayManagerSettings.BadKeyException e) { Slog.e(TAG, "failed to remove overlay", e); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5eae9c7ad99c..2ee484d32cd8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1990,31 +1990,31 @@ public class PackageManagerService extends IPackageManager.Stub // Work that needs to happen on first install within each user if (firstUserIds != null && firstUserIds.length > 0) { - synchronized (mPackages) { - for (int userId : firstUserIds) { - // If this app is a browser and it's newly-installed for some - // users, clear any default-browser state in those users. The - // app's nature doesn't depend on the user, so we can just check - // its browser nature in any user and generalize. - if (packageIsBrowser(packageName, userId)) { - // If this browser is restored from user's backup, do not clear - // default-browser state for this user + for (int userId : firstUserIds) { + // If this app is a browser and it's newly-installed for some + // users, clear any default-browser state in those users. The + // app's nature doesn't depend on the user, so we can just check + // its browser nature in any user and generalize. + if (packageIsBrowser(packageName, userId)) { + // If this browser is restored from user's backup, do not clear + // default-browser state for this user + synchronized (mPackages) { final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); if (pkgSetting.getInstallReason(userId) != PackageManager.INSTALL_REASON_DEVICE_RESTORE) { setDefaultBrowserAsyncLPw(null, userId); } } + } - // We may also need to apply pending (restored) runtime permission grants - // within these users. - mPermissionManager.restoreDelayedRuntimePermissions(packageName, - UserHandle.of(userId)); + // We may also need to apply pending (restored) runtime permission grants + // within these users. + mPermissionManager.restoreDelayedRuntimePermissions(packageName, + UserHandle.of(userId)); - // Persistent preferred activity might have came into effect due to this - // install. - updateDefaultHomeLPw(userId); - } + // Persistent preferred activity might have came into effect due to this + // install. + updateDefaultHomeNotLocked(userId); } } @@ -2801,6 +2801,11 @@ public class PackageManagerService extends IPackageManager.Stub if (disabledPs.codePath == null || !disabledPs.codePath.exists() || disabledPs.pkg == null) { possiblyDeletedUpdatedSystemApps.add(ps.name); + } else { + // We're expecting that the system app should remain disabled, but add + // it to expecting better to recover in case the data version cannot + // be scanned. + mExpectingBetter.put(disabledPs.name, disabledPs.codePath); } } } @@ -5158,7 +5163,7 @@ public class PackageManagerService extends IPackageManager.Stub getPackagesUsingSharedLibraryLPr(libInfo, flags, userId), (libInfo.getDependencies() == null ? null - : new ArrayList(libInfo.getDependencies()))); + : new ArrayList<>(libInfo.getDependencies()))); if (result == null) { result = new ArrayList<>(); @@ -6475,8 +6480,8 @@ public class PackageManagerService extends IPackageManager.Stub final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); // Find any earlier preferred or last chosen entries and nuke them - findPreferredActivity(intent, resolvedType, - flags, query, 0, false, true, false, userId); + findPreferredActivityNotLocked( + intent, resolvedType, flags, query, 0, false, true, false, userId); // Add the new activity as the last chosen for this filter addPreferredActivityInternal(filter, match, null, activity, false, userId, "Setting last chosen"); @@ -6491,8 +6496,8 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent); final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); - return findPreferredActivity(intent, resolvedType, flags, query, 0, - false, false, false, userId); + return findPreferredActivityNotLocked( + intent, resolvedType, flags, query, 0, false, false, false, userId); } /** @@ -6605,7 +6610,7 @@ public class PackageManagerService extends IPackageManager.Stub } // If we have saved a preference for a preferred activity for // this Intent, use that. - ResolveInfo ri = findPreferredActivity(intent, resolvedType, + ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType, flags, query, r0.priority, true, false, debug, userId); if (ri != null) { return ri; @@ -6744,9 +6749,14 @@ public class PackageManagerService extends IPackageManager.Stub } // TODO: handle preferred activities missing while user has amnesia - ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, + /** <b>must not hold {@link #mPackages}</b> */ + ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int priority, boolean always, boolean removeMatches, boolean debug, int userId) { + if (Thread.holdsLock(mPackages)) { + Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + + " is holding mPackages", new Throwable()); + } if (!sUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); // Do NOT hold the packages lock; this calls up into the settings provider which @@ -9329,6 +9339,7 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_UPDATE_SIGNATURE, currentTime, user); if (scanResult.success) { synchronized (mPackages) { + boolean appIdCreated = false; try { final String pkgName = scanResult.pkgSetting.name; final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked( @@ -9341,11 +9352,12 @@ public class PackageManagerService extends IPackageManager.Stub Collections.singletonMap(pkgName, getSharedLibLatestVersionSetting(scanResult))), mSettings.mKeySetManagerService); - prepareScanResultLocked(scanResult); - commitReconciledScanResultLocked( - reconcileResult.get(pkgName)); + appIdCreated = optimisticallyRegisterAppId(scanResult); + commitReconciledScanResultLocked(reconcileResult.get(pkgName)); } catch (PackageManagerException e) { - unprepareScanResultLocked(scanResult); + if (appIdCreated) { + cleanUpAppIdCreation(scanResult); + } throw e; } } @@ -10832,27 +10844,32 @@ public class PackageManagerService extends IPackageManager.Stub } - /** Prepares the system to commit a {@link ScanResult} in a way that will not fail. */ - private void prepareScanResultLocked(@NonNull ScanResult result) + /** + * Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering + * the app ID required for reconcile. + * @return {@code true} if a new app ID was registered and will need to be cleaned up on + * failure. + */ + private boolean optimisticallyRegisterAppId(@NonNull ScanResult result) throws PackageManagerException { if (!result.existingSettingCopied) { // THROWS: when we can't allocate a user id. add call to check if there's // enough space to ensure we won't throw; otherwise, don't modify state - mSettings.registerAppIdLPw(result.pkgSetting); + return mSettings.registerAppIdLPw(result.pkgSetting); } + return false; } /** - * Reverts any changes to the system that were made by - * {@link #prepareScanResultLocked(ScanResult)} + * Reverts any app ID creation that were made by + * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the + * referenced method returned true. */ - private void unprepareScanResultLocked(@NonNull ScanResult result) { - if (!result.existingSettingCopied) { - // iff we've acquired an app ID for a new package setting, remove it so that it can be - // acquired by another request. - if (result.pkgSetting.appId > 0) { - mSettings.removeAppIdLPw(result.pkgSetting.appId); - } + private void cleanUpAppIdCreation(@NonNull ScanResult result) { + // iff we've acquired an app ID for a new package setting, remove it so that it can be + // acquired by another request. + if (result.pkgSetting.appId > 0) { + mSettings.removeAppIdLPw(result.pkgSetting.appId); } } @@ -16696,6 +16713,7 @@ public class PackageManagerService extends IPackageManager.Stub final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size()); final Map<String, PackageSetting> lastStaticSharedLibSettings = new ArrayMap<>(requests.size()); + final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size()); boolean success = false; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI"); @@ -16735,7 +16753,7 @@ public class PackageManagerService extends IPackageManager.Stub + " in multi-package install request."); return; } - prepareScanResultLocked(result); + createdAppId.put(packageName, optimisticallyRegisterAppId(result)); versionInfos.put(result.pkgSetting.pkg.packageName, getSettingsVersionForPackage(result.pkgSetting.pkg)); if (result.staticSharedLibraryInfo != null) { @@ -16792,7 +16810,9 @@ public class PackageManagerService extends IPackageManager.Stub } finally { if (!success) { for (ScanResult result : preparedScans.values()) { - unprepareScanResultLocked(result); + if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) { + cleanUpAppIdCreation(result); + } } } for (PrepareResult result : prepareResults.values()) { @@ -18599,10 +18619,10 @@ public class PackageManagerService extends IPackageManager.Stub int removedAppId = -1; // writer - synchronized (mPackages) { - boolean installedStateChanged = false; - if (deletedPs != null) { - if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) { + boolean installedStateChanged = false; + if (deletedPs != null) { + if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { + synchronized (mPackages) { clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL); clearDefaultBrowserIfNeeded(packageName); mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); @@ -18633,26 +18653,34 @@ public class PackageManagerService extends IPackageManager.Stub } } } - clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL); } - // make sure to preserve per-user disabled state if this removal was just - // a downgrade of a system app to the factory package - if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) { + final SparseBooleanArray changedUsers = new SparseBooleanArray(); + clearPackagePreferredActivitiesLPw( + deletedPs.name, changedUsers, UserHandle.USER_ALL); + if (changedUsers.size() > 0) { + updateDefaultHomeNotLocked(changedUsers); + postPreferredActivityChangedBroadcast(UserHandle.USER_ALL); + } + } + // make sure to preserve per-user disabled state if this removal was just + // a downgrade of a system app to the factory package + if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) { + if (DEBUG_REMOVE) { + Slog.d(TAG, "Propagating install state across downgrade"); + } + for (int userId : allUserHandles) { + final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId); if (DEBUG_REMOVE) { - Slog.d(TAG, "Propagating install state across downgrade"); + Slog.d(TAG, " user " + userId + " => " + installed); } - for (int userId : allUserHandles) { - final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId); - if (DEBUG_REMOVE) { - Slog.d(TAG, " user " + userId + " => " + installed); - } - if (installed != deletedPs.getInstalled(userId)) { - installedStateChanged = true; - } - deletedPs.setInstalled(installed, userId); + if (installed != deletedPs.getInstalled(userId)) { + installedStateChanged = true; } + deletedPs.setInstalled(installed, userId); } } + } + synchronized (mPackages) { // can downgrade to reader if (writeSettings) { // Save settings now @@ -19138,22 +19166,22 @@ public class PackageManagerService extends IPackageManager.Stub final UserHandle user = action.user; final int flags = action.flags; final boolean systemApp = isSystemApp(ps); - synchronized (mPackages) { - if (ps.parentPackageName != null - && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) { - if (DEBUG_REMOVE) { - Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:" - + ((user == null) ? UserHandle.USER_ALL : user)); - } - final int removedUserId = (user != null) ? user.getIdentifier() - : UserHandle.USER_ALL; + if (ps.parentPackageName != null + && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) { + if (DEBUG_REMOVE) { + Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:" + + ((user == null) ? UserHandle.USER_ALL : user)); + } + final int removedUserId = (user != null) ? user.getIdentifier() + : UserHandle.USER_ALL; - clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags); + clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags); + synchronized (mPackages) { markPackageUninstalledForUserLPw(ps, user); scheduleWritePackageRestrictionsLocked(user); - return; } + return; } final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier(); @@ -19167,6 +19195,7 @@ public class PackageManagerService extends IPackageManager.Stub // its data. If this is a system app, we only allow this to happen if // they have set the special DELETE_SYSTEM_APP which requests different // semantics than normal for uninstalling system apps. + final boolean clearPackageStateAndReturn; synchronized (mPackages) { markPackageUninstalledForUserLPw(ps, user); if (!systemApp) { @@ -19177,15 +19206,14 @@ public class PackageManagerService extends IPackageManager.Stub // we need to do is clear this user's data and save that // it is uninstalled. if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users"); - clearPackageStateForUserLIF(ps, userId, outInfo, flags); - scheduleWritePackageRestrictionsLocked(user); - return; + clearPackageStateAndReturn = true; } else { // We need to set it back to 'installed' so the uninstall // broadcasts will be sent correctly. if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete"); ps.setInstalled(true, userId); mSettings.writeKernelMappingLPr(ps); + clearPackageStateAndReturn = false; } } else { // This is a system app, so we assume that the @@ -19193,10 +19221,15 @@ public class PackageManagerService extends IPackageManager.Stub // we need to do is clear this user's data and save that // it is uninstalled. if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app"); - clearPackageStateForUserLIF(ps, userId, outInfo, flags); + clearPackageStateAndReturn = true; + } + } + if (clearPackageStateAndReturn) { + clearPackageStateForUserLIF(ps, userId, outInfo, flags); + synchronized (mPackages) { scheduleWritePackageRestrictionsLocked(user); - return; } + return; } } @@ -19330,10 +19363,17 @@ public class PackageManagerService extends IPackageManager.Stub destroyAppDataLIF(pkg, nextUserId, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); clearDefaultBrowserIfNeededForUser(ps.name, nextUserId); - synchronized (mPackages) { - if (clearPackagePreferredActivitiesLPw(ps.name, nextUserId)) { + removeKeystoreDataIfNeeded(nextUserId, ps.appId); + final SparseBooleanArray changedUsers = new SparseBooleanArray(); + clearPackagePreferredActivitiesLPw(ps.name, changedUsers, nextUserId); + if (changedUsers.size() > 0) { + updateDefaultHomeNotLocked(changedUsers); + postPreferredActivityChangedBroadcast(nextUserId); + synchronized (mPackages) { scheduleWritePackageRestrictionsLocked(nextUserId); } + } + synchronized (mPackages) { resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, nextUserId); } // Also delete contributed media, when requested @@ -19796,33 +19836,34 @@ public class PackageManagerService extends IPackageManager.Stub int callingUid = Binder.getCallingUid(); mPermissionManager.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "add preferred activity"); + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.SET_PREFERRED_APPLICATIONS) + != PackageManager.PERMISSION_GRANTED) { + if (getUidTargetSdkVersionLockedLPr(callingUid) + < Build.VERSION_CODES.FROYO) { + Slog.w(TAG, "Ignoring addPreferredActivity() from uid " + + callingUid); + return; + } + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); + } if (filter.countActions() == 0) { Slog.w(TAG, "Cannot set a preferred activity with no filter actions"); return; } - synchronized (mPackages) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS) - != PackageManager.PERMISSION_GRANTED) { - if (getUidTargetSdkVersionLockedLPr(callingUid) - < Build.VERSION_CODES.FROYO) { - Slog.w(TAG, "Ignoring addPreferredActivity() from uid " - + callingUid); - return; - } - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); - } - - PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId); + if (DEBUG_PREFERRED) { Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user " + userId + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); + } + if (!updateDefaultHomeNotLocked(userId)) { + postPreferredActivityChangedBroadcast(userId); + } + synchronized (mPackages) { + final PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId); pir.addFilter(new PreferredActivity(filter, match, set, activity, always)); scheduleWritePackageRestrictionsLocked(userId); - if (!updateDefaultHomeLPw(userId)) { - postPreferredActivityChangedBroadcast(userId); - } } } @@ -19963,25 +20004,24 @@ public class PackageManagerService extends IPackageManager.Stub && filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) { return; } - int user = UserHandle.getCallingUserId(); - if (clearPackagePreferredActivitiesLPw(packageName, user)) { - scheduleWritePackageRestrictionsLocked(user); + } + int callingUserId = UserHandle.getCallingUserId(); + final SparseBooleanArray changedUsers = new SparseBooleanArray(); + clearPackagePreferredActivitiesLPw(packageName, changedUsers, callingUserId); + if (changedUsers.size() > 0) { + updateDefaultHomeNotLocked(changedUsers); + postPreferredActivityChangedBroadcast(callingUserId); + synchronized (mPackages) { + scheduleWritePackageRestrictionsLocked(callingUserId); } } } /** This method takes a specific user id as well as UserHandle.USER_ALL. */ @GuardedBy("mPackages") - boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) { - return clearPackagePreferredActivitiesLPw(packageName, false, userId); - } - - /** This method takes a specific user id as well as UserHandle.USER_ALL. */ - @GuardedBy("mPackages") - private boolean clearPackagePreferredActivitiesLPw(String packageName, - boolean skipUpdateDefaultHome, int userId) { + private void clearPackagePreferredActivitiesLPw(String packageName, + @NonNull SparseBooleanArray outUserChanged, int userId) { ArrayList<PreferredActivity> removed = null; - boolean changed = false; for (int i=0; i<mSettings.mPreferredActivities.size(); i++) { final int thisUserId = mSettings.mPreferredActivities.keyAt(i); PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i); @@ -20007,16 +20047,9 @@ public class PackageManagerService extends IPackageManager.Stub PreferredActivity pa = removed.get(j); pir.removeFilter(pa); } - changed = true; - if (!skipUpdateDefaultHome) { - updateDefaultHomeLPw(thisUserId); - } + outUserChanged.put(thisUserId, true); } } - if (changed) { - postPreferredActivityChangedBroadcast(userId); - } - return changed; } /** This method takes a specific user id as well as UserHandle.USER_ALL. */ @@ -20069,21 +20102,27 @@ public class PackageManagerService extends IPackageManager.Stub final long identity = Binder.clearCallingIdentity(); // writer try { + final SparseBooleanArray changedUsers = new SparseBooleanArray(); + clearPackagePreferredActivitiesLPw(null, changedUsers, userId); + if (changedUsers.size() > 0) { + postPreferredActivityChangedBroadcast(userId); + } synchronized (mPackages) { - clearPackagePreferredActivitiesLPw(null, true, userId); mSettings.applyDefaultPreferredAppsLPw(userId); - updateDefaultHomeLPw(userId); - // TODO: We have to reset the default SMS and Phone. This requires - // significant refactoring to keep all default apps in the package - // manager (cleaner but more work) or have the services provide - // callbacks to the package manager to request a default app reset. - setDefaultBrowserPackageName(null, userId); clearIntentFilterVerificationsLPw(userId); primeDomainVerificationsLPw(userId); resetUserChangesToRuntimePermissionsAndFlagsLPw(userId); - scheduleWritePackageRestrictionsLocked(userId); } + updateDefaultHomeNotLocked(userId); + // TODO: We have to reset the default SMS and Phone. This requires + // significant refactoring to keep all default apps in the package + // manager (cleaner but more work) or have the services provide + // callbacks to the package manager to request a default app reset. + setDefaultBrowserPackageName(null, userId); resetNetworkPolicies(userId); + synchronized (mPackages) { + scheduleWritePackageRestrictionsLocked(userId); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -20133,15 +20172,17 @@ public class PackageManagerService extends IPackageManager.Stub Slog.w(TAG, "Cannot set a preferred activity with no filter actions"); return; } - synchronized (mPackages) { - Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId + - ":"); + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Adding persistent preferred activity " + activity + + " for user " + userId + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); + } + updateDefaultHomeNotLocked(userId); + postPreferredActivityChangedBroadcast(userId); + synchronized (mPackages) { mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter( new PersistentPreferredActivity(filter, activity)); scheduleWritePackageRestrictionsLocked(userId); - postPreferredActivityChangedBroadcast(userId); - updateDefaultHomeLPw(userId); } } @@ -20181,11 +20222,12 @@ public class PackageManagerService extends IPackageManager.Stub changed = true; } } - - if (changed) { + } + if (changed) { + updateDefaultHomeNotLocked(userId); + postPreferredActivityChangedBroadcast(userId); + synchronized (mPackages) { scheduleWritePackageRestrictionsLocked(userId); - postPreferredActivityChangedBroadcast(userId); - updateDefaultHomeLPw(userId); } } } @@ -20273,8 +20315,8 @@ public class PackageManagerService extends IPackageManager.Stub (readParser, readUserId) -> { synchronized (mPackages) { mSettings.readPreferredActivitiesLPw(readParser, readUserId); - updateDefaultHomeLPw(readUserId); } + updateDefaultHomeNotLocked(readUserId); }); } catch (Exception e) { if (DEBUG_BACKUP) { @@ -20601,29 +20643,55 @@ public class PackageManagerService extends IPackageManager.Stub return null; } + /** <b>must not hold {@link #mPackages}</b> */ + private void updateDefaultHomeNotLocked(SparseBooleanArray userIds) { + if (Thread.holdsLock(mPackages)) { + Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + + " is holding mPackages", new Throwable()); + } + for (int i = userIds.size() - 1; i >= 0; --i) { + final int userId = userIds.keyAt(i); + updateDefaultHomeNotLocked(userId); + } + } + /** + * <b>must not hold {@link #mPackages}</b> + * * @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled. */ - private boolean updateDefaultHomeLPw(int userId) { - Intent intent = getHomeIntent(); - List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null, + private boolean updateDefaultHomeNotLocked(int userId) { + if (Thread.holdsLock(mPackages)) { + Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + + " is holding mPackages", new Throwable()); + } + final Intent intent = getHomeIntent(); + final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null, PackageManager.GET_META_DATA, userId); - ResolveInfo preferredResolveInfo = findPreferredActivity(intent, null, 0, resolveInfos, - 0, true, false, false, userId); - String packageName = preferredResolveInfo != null + final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked( + intent, null, 0, resolveInfos, 0, true, false, false, userId); + final String packageName = preferredResolveInfo != null && preferredResolveInfo.activityInfo != null ? preferredResolveInfo.activityInfo.packageName : null; - String currentPackageName = mDefaultHomeProvider.getDefaultHome(userId); + final PackageManagerInternal.DefaultHomeProvider provider; + synchronized (mPackages) { + provider = mDefaultHomeProvider; + } + if (provider == null) { + Slog.e(TAG, "Default home provider has not been set"); + return false; + } + final String currentPackageName = provider.getDefaultHome(userId); if (TextUtils.equals(currentPackageName, packageName)) { return false; } - String[] callingPackages = getPackagesForUid(Binder.getCallingUid()); + final String[] callingPackages = getPackagesForUid(Binder.getCallingUid()); if (callingPackages != null && ArrayUtils.contains(callingPackages, mRequiredPermissionControllerPackage)) { // PermissionController manages default home directly. return false; } - mDefaultHomeProvider.setDefaultHomeAsync(packageName, userId, (successful) -> { + provider.setDefaultHomeAsync(packageName, userId, (successful) -> { if (successful) { postPreferredActivityChangedBroadcast(userId); } @@ -20699,8 +20767,16 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public String getAttentionServicePackageName() { - return mContext.getString(R.string.config_defaultAttentionService); + public @Nullable String getAttentionServicePackageName() { + final String flattenedComponentName = + mContext.getString(R.string.config_defaultAttentionService); + if (flattenedComponentName != null) { + ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName); + if (componentName != null && componentName.getPackageName() != null) { + return componentName.getPackageName(); + } + } + return null; } private @Nullable String getDocumenterPackageName() { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 41a8a776e3f7..dae07bdc37d5 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -810,15 +810,20 @@ public final class Settings { /** * Registers a user ID with the system. Potentially allocates a new user ID. + * @return {@code true} if a new app ID was created in the process. {@code false} can be + * returned in the case that a shared user ID already exists or the explicit app ID is + * already registered. * @throws PackageManagerException If a user ID could not be allocated. */ - void registerAppIdLPw(PackageSetting p) throws PackageManagerException { + boolean registerAppIdLPw(PackageSetting p) throws PackageManagerException { + final boolean createdNew; if (p.appId == 0) { // Assign new user ID p.appId = acquireAndRegisterNewAppIdLPw(p); + createdNew = true; } else { // Add new setting to list of user IDs - registerExistingAppIdLPw(p.appId, p, p.name); + createdNew = registerExistingAppIdLPw(p.appId, p, p.name); } if (p.appId < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, @@ -826,6 +831,7 @@ public final class Settings { throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Package " + p.name + " could not be assigned a valid UID"); } + return createdNew; } /** diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 72d543862c58..803ab2d299e2 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -261,13 +261,13 @@ public class StagingManager { if (storageManager.supportsCheckpoint()) { storageManager.startCheckpoint(1 /* numRetries */); } - } catch (RemoteException e) { + } catch (Exception e) { // TODO(b/130190815) make a RemoteException again // While StorageManager lives in the same process, the native implementation // it calls through lives in 'vold'; so, this call can fail if 'vold' isn't // reachable. // Since we can live without filesystem checkpointing, just warn in this case // and continue. - Slog.w(TAG, "Could not start filesystem checkpoint."); + Slog.w(TAG, "Could not start filesystem checkpoint:", e); } session.setStagedSessionReady(); diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index d9d21babe210..5e829b2d6067 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -16,9 +16,14 @@ package com.android.server.power; +import static android.provider.Settings.System.ADAPTIVE_SLEEP; + +import android.Manifest; import android.attention.AttentionManagerInternal; import android.attention.AttentionManagerInternal.AttentionCallbackInternal; +import android.content.ContentResolver; import android.content.Context; +import android.content.pm.PackageManager; import android.database.ContentObserver; import android.os.Handler; import android.os.PowerManager; @@ -83,6 +88,12 @@ public class AttentionDetector { @VisibleForTesting protected AttentionManagerInternal mAttentionManager; + @VisibleForTesting + protected PackageManager mPackageManager; + + @VisibleForTesting + protected ContentResolver mContentResolver; + /** * Current wakefulness of the device. {@see PowerManagerInternal} */ @@ -137,6 +148,8 @@ public class AttentionDetector { public void systemReady(Context context) { updateEnabledFromSettings(context); + mPackageManager = context.getPackageManager(); + mContentResolver = context.getContentResolver(); mAttentionManager = LocalServices.getService(AttentionManagerInternal.class); mMaximumExtensionMillis = context.getResources().getInteger( com.android.internal.R.integer.config_attentionMaximumExtension); @@ -162,6 +175,11 @@ public class AttentionDetector { return nextScreenDimming; } + if (!serviceHasSufficientPermissions()) { + Settings.System.putInt(mContentResolver, ADAPTIVE_SLEEP, 0); + return nextScreenDimming; + } + final long now = SystemClock.uptimeMillis(); final long whenToCheck = nextScreenDimming - getAttentionTimeout(); final long whenToStopExtending = mLastUserActivityTime + mMaximumExtensionMillis; @@ -263,6 +281,18 @@ public class AttentionDetector { return mAttentionManager != null && mAttentionManager.isAttentionServiceSupported(); } + /** + * Returns {@code true} if the attention service has sufficient permissions, disables the + * depending features otherwise. + */ + @VisibleForTesting + boolean serviceHasSufficientPermissions() { + final String attentionPackage = mPackageManager.getAttentionServicePackageName(); + return attentionPackage != null && mPackageManager.checkPermission( + Manifest.permission.CAMERA, attentionPackage) + == PackageManager.PERMISSION_GRANTED; + } + public void dump(PrintWriter pw) { pw.print("AttentionDetector:"); pw.print(" mMaximumExtensionMillis=" + mMaximumExtensionMillis); diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 96924c04e5e1..da9bc1646f4b 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -64,6 +64,7 @@ import android.os.BatteryStatsInternal; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.CoolingDevice; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; @@ -92,6 +93,7 @@ import android.os.UserManager; import android.os.storage.DiskInfo; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import android.provider.Settings; import android.stats.storage.StorageEnums; import android.telephony.ModemActivityInfo; import android.telephony.TelephonyManager; @@ -1797,6 +1799,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { e.writeInt(temp.getType()); e.writeString(temp.getName()); e.writeInt((int) (temp.getValue() * 10)); + e.writeInt(temp.getStatus()); + pulledData.add(e); + } + } catch (RemoteException e) { + // Should not happen. + Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures."); + } finally { + Binder.restoreCallingIdentity(callingToken); + } + } + + private void pullCoolingDevices(int tagId, long elapsedNanos, long wallClockNanos, + List<StatsLogEventWrapper> pulledData) { + long callingToken = Binder.clearCallingIdentity(); + try { + List<CoolingDevice> devices = sThermalService.getCurrentCoolingDevices(); + for (CoolingDevice device : devices) { + StatsLogEventWrapper e = + new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeInt(device.getType()); + e.writeString(device.getName()); + e.writeInt((int) (device.getValue())); pulledData.add(e); } } catch (RemoteException e) { @@ -2057,6 +2081,43 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + private void pullFaceSettings(int tagId, long elapsedNanos, long wallClockNanos, + List<StatsLogEventWrapper> pulledData) { + long callingToken = Binder.clearCallingIdentity(); + try { + List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); + int numUsers = users.size(); + for (int userNum = 0; userNum < numUsers; userNum++) { + int userId = users.get(userNum).getUserHandle().getIdentifier(); + + StatsLogEventWrapper e = + new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, + userId) != 0); + e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, + 0, userId) != 0); + e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 1, + userId) != 0); + e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, + userId) != 0); + e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, + userId) != 0); + e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, + userId) != 0); + + pulledData.add(e); + } + } finally { + Binder.restoreCallingIdentity(callingToken); + } + } + /** * Pulls various data. */ @@ -2233,6 +2294,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullTemperature(tagId, elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.COOLING_DEVICE: { + pullCoolingDevices(tagId, elapsedNanos, wallClockNanos, ret); + break; + } case StatsLog.DEBUG_ELAPSED_CLOCK: { pullDebugElapsedClock(tagId, elapsedNanos, wallClockNanos, ret); break; @@ -2261,6 +2326,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullAppsOnExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.FACE_SETTINGS: { + pullFaceSettings(tagId, elapsedNanos, wallClockNanos, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; @@ -2493,12 +2562,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override public void notifyThrottling(Temperature temp) { - boolean isThrottling = temp.getStatus() >= Temperature.THROTTLING_SEVERE; StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(), - isThrottling ? - StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__START : - StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__STOP, - temp.getValue()); + StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__UNKNOWN, + temp.getValue(), temp.getStatus(), temp.getName()); } } diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index d916e39c2531..10afbef12623 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -26,20 +26,6 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TR import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_FLAGS; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_FULLSCREEN; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_LAUNCH_MODE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_PROCESS_NAME; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_REAL_ACTIVITY; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_PACKAGE_NAME; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW; @@ -62,12 +48,7 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_PROC_STATE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_PACKAGE_NAME; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_SHORT_COMPONENT_NAME; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_PROC_STATE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_WHITELIST_TAG; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_FILTER; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_REASON; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH; @@ -671,6 +652,11 @@ class ActivityMetricsLogger { final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(index); final int type = getTransitionType(info); if (type == INVALID_TRANSITION_TYPE) { + if (DEBUG_METRICS) { + Slog.i(TAG, "invalid transition type" + + " processRunning=" + info.currentTransitionProcessRunning + + " startResult=" + info.startResult); + } return; } @@ -921,7 +907,10 @@ class ActivityMetricsLogger { } else if (info.startResult == START_TASK_TO_FRONT) { return TYPE_TRANSITION_HOT_LAUNCH; } - } else if (info.startResult == START_SUCCESS) { + } else if (info.startResult == START_SUCCESS + || (info.startResult == START_TASK_TO_FRONT)) { + // TaskRecord may still exist when cold launching an activity and the start + // result will be set to START_TASK_TO_FRONT. Treat this as a COLD launch. return TYPE_TRANSITION_COLD_LAUNCH; } return INVALID_TRANSITION_TYPE; diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 419f5be5bbc8..76b0351fe1f6 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2753,7 +2753,7 @@ class ActivityStack extends ConfigurationContainer { // happens to be sitting towards the end. if (next.attachedToProcess()) { next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* updateLru */, true /* activityChange */, false /* updateOomAdj */); + true /* activityChange */, false /* updateOomAdj */); } if (lastResumed != null) { lastResumed.setWillCloseOrEnterPip(true); @@ -2903,7 +2903,7 @@ class ActivityStack extends ConfigurationContainer { next.setState(RESUMED, "resumeTopActivityInnerLocked"); next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* updateLru */, true /* activityChange */, true /* updateOomAdj */); + true /* activityChange */, true /* updateOomAdj */); updateLRUListLocked(next); // Have the window manager re-evaluate the orientation of @@ -4600,7 +4600,8 @@ class ActivityStack extends ConfigurationContainer { // Update any services we are bound to that might care about whether // their client may have activities. // No longer have activities, so update LRU list and oom adj. - r.app.updateProcessInfo(true, true, false, true); + r.app.updateProcessInfo(true /* updateServiceConnectionActivities */, + false /* activityChange */, true /* updateOomAdj */); } } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index a9d76a61f4f5..5790a1b39493 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -769,14 +769,12 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { + " old=" + r.app + " new=" + proc); } - proc.clearWaitingToKill(); r.launchCount++; r.lastLaunchTime = SystemClock.uptimeMillis(); if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r); proc.addActivityIfNeeded(r); - proc.updateProcessInfo(false, true, true, true); final LockTaskController lockTaskController = mService.getLockTaskController(); if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE @@ -814,7 +812,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { r.forceNewConfig = false; mService.getAppWarningsLocked().onStartActivity(r); r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); - ProfilerInfo profilerInfo = proc.onStartActivity(mService.mTopProcessState); // Because we could be starting an Activity in the system process this may not go // across a Binder interface which would create a new Configuration. Consequently @@ -840,7 +837,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(), r.icicle, r.persistentState, results, newIntents, - dc.isNextTransitionForward(), profilerInfo)); + dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded())); // Set desired final state. final ActivityLifecycleItem lifecycleItem; @@ -910,6 +907,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { "Moving to PAUSED: " + r + " (starting in paused state)"); r.setState(PAUSED, "realStartActivityLocked"); } + // Perform OOM scoring after the activity state is set, so the process can be updated with + // the latest state. + proc.onStartActivity(mService.mTopProcessState, r.info); // Launch the new version setup screen if needed. We do this -after- // launching the initial activity (that is, home), so that it can have @@ -960,13 +960,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { boolean knownToBeDead = false; if (wpc != null && wpc.hasThread()) { try { - if ((r.info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0 - || !"android".equals(r.info.packageName)) { - // Don't add this if it is a platform component that is marked to run in - // multiple processes, because this is actually part of the framework so doesn't - // make sense to track as a separate apk in the process. - wpc.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode); - } realStartActivityLocked(r, wpc, andResume, checkConfig); return; } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index b287a0b011e7..7eac07c47741 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -457,7 +457,7 @@ public class ActivityStartController { "pendingActivityLaunch"); try { starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, - resume, pal.r.pendingOptions, null, null /* outRecords */); + resume, pal.r.pendingOptions, null); } catch (Exception e) { Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e); pal.sendErrorResult(e.getMessage()); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 473a8757f09f..4ef8753bd131 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -544,11 +544,17 @@ class ActivityStarter { */ int startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, - ActivityRecord[] outActivity) { + int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) { try { - return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, - doResume, options, inTask, outActivity); + mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent); + mLastStartReason = "startResolvedActivity"; + mLastStartActivityTimeMs = System.currentTimeMillis(); + mLastStartActivityRecord[0] = r; + mLastStartActivityResult = startActivity(r, sourceRecord, voiceSession, voiceInteractor, + startFlags, doResume, options, inTask, mLastStartActivityRecord); + mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(mLastStartActivityResult, + mLastStartActivityRecord[0]); + return mLastStartActivityResult; } finally { onExecutionComplete(); } @@ -937,7 +943,7 @@ class ActivityStarter { || callingUid == Process.NFC_UID) { return false; } - // don't abort if the callingUid is in the foreground or is a persistent system process + // don't abort if the callingUid has a visible window or is a persistent system process final int callingUidProcState = mService.getUidState(callingUid); final boolean callingUidHasAnyVisibleWindow = mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid); @@ -946,7 +952,7 @@ class ActivityStarter { || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; final boolean isCallingUidPersistentSystemProcess = (callingUid == Process.SYSTEM_UID) || callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; - if (isCallingUidForeground || isCallingUidPersistentSystemProcess) { + if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) { return false; } // take realCallingUid into consideration @@ -965,8 +971,9 @@ class ActivityStarter { : (realCallingUid == Process.SYSTEM_UID) || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; if (realCallingUid != callingUid) { - // don't abort if the realCallingUid is in the foreground and callingUid isn't - if (isRealCallingUidForeground) { + // don't abort if the realCallingUid has a visible window, unless realCallingUid is + // SYSTEM_UID, in which case it start needs to be explicitly whitelisted + if (realCallingUidHasAnyVisibleWindow && realCallingUid != Process.SYSTEM_UID) { return false; } // if the realCallingUid is a persistent system process, abort if the IntentSender @@ -980,35 +987,6 @@ class ActivityStarter { return false; } } - // If we don't have callerApp at this point, no caller was provided to startActivity(). - // That's the case for PendingIntent-based starts, since the creator's process might not be - // up and alive. If that's the case, we retrieve the WindowProcessController for the send() - // caller, so that we can make the decision based on its foreground/whitelisted state. - if (callerApp == null) { - callerApp = mService.getProcessController(realCallingPid, realCallingUid); - } - if (callerApp != null) { - // don't abort if the callerApp has any visible activity - if (callerApp.hasForegroundActivities()) { - return false; - } - // don't abort if the callerApp is instrumenting with background activity starts privs - if (callerApp.isInstrumentingWithBackgroundActivityStartPrivileges()) { - return false; - } - // don't abort if the caller is currently temporarily whitelisted - if (callerApp.areBackgroundActivityStartsAllowed()) { - return false; - } - // don't abort if the caller has an activity in any foreground task - if (callerApp.hasActivityInVisibleTask()) { - return false; - } - // don't abort if the caller is bound by a UID that's currently foreground - if (isBoundByForegroundUid(callerApp)) { - return false; - } - } // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid) == PERMISSION_GRANTED) { @@ -1033,6 +1011,33 @@ class ActivityStarter { + " temporarily whitelisted. This will not be supported in future Q builds."); return false; } + // If we don't have callerApp at this point, no caller was provided to startActivity(). + // That's the case for PendingIntent-based starts, since the creator's process might not be + // up and alive. If that's the case, we retrieve the WindowProcessController for the send() + // caller, so that we can make the decision based on its foreground/whitelisted state. + int callerAppUid = callingUid; + if (callerApp == null) { + callerApp = mService.getProcessController(realCallingPid, realCallingUid); + callerAppUid = realCallingUid; + } + // don't abort if the callerApp or other processes of that uid are whitelisted in any way + if (callerApp != null) { + // first check the original calling process + if (callerApp.areBackgroundActivityStartsAllowed()) { + return false; + } + // only if that one wasn't whitelisted, check the other ones + final ArraySet<WindowProcessController> uidProcesses = + mService.mProcessMap.getProcesses(callerAppUid); + if (uidProcesses != null) { + for (int i = uidProcesses.size() - 1; i >= 0; i--) { + final WindowProcessController proc = uidProcesses.valueAt(i); + if (proc != callerApp && proc.areBackgroundActivityStartsAllowed()) { + return false; + } + } + } + } // anything that has fallen through would currently be aborted Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage + "; callingUid: " + callingUid @@ -1057,18 +1062,6 @@ class ActivityStarter { return true; } - private boolean isBoundByForegroundUid(WindowProcessController callerApp) { - final ArraySet<Integer> boundClientUids = callerApp.getBoundClientUids(); - for (int i = boundClientUids.size() - 1; i >= 0; --i) { - final int uid = boundClientUids.valueAt(i); - if (mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid) - || mService.getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) { - return true; - } - } - return false; - } - // TODO: remove this toast after feature development is done void showBackgroundActivityBlockedToast(boolean abort, String callingPackage) { final Resources res = mService.mContext.getResources(); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7d25466bf348..48aee200ccc0 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -503,7 +503,7 @@ public abstract class ActivityTaskManagerInternal { public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution); - /** Returns true if uid has a visible window or its process is in a top state. */ + /** Returns true if uid is considered foreground for activity start purposes. */ public abstract boolean isUidForeground(int uid); /** diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index b4249046c1b5..3fa026873953 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -373,8 +373,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>(); /** All processes currently running that might have a window organized by name. */ final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>(); - /** All processes we currently have running mapped by pid */ - final SparseArray<WindowProcessController> mPidMap = new SparseArray<>(); + /** All processes we currently have running mapped by pid and uid */ + final WindowProcessControllerMap mProcessMap = new WindowProcessControllerMap(); /** This is the process holding what we currently consider to be the "home" activity. */ WindowProcessController mHomeProcess; /** The currently running heavy-weight process, if any. */ @@ -913,7 +913,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return getGlobalConfiguration(); } synchronized (mGlobalLock) { - final WindowProcessController app = mPidMap.get(pid); + final WindowProcessController app = mProcessMap.getProcess(pid); return app != null ? app.getConfiguration() : getGlobalConfiguration(); } } @@ -4640,7 +4640,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { enforceSystemHasVrFeature(); synchronized (mGlobalLock) { final int pid = Binder.getCallingPid(); - final WindowProcessController wpc = mPidMap.get(pid); + final WindowProcessController wpc = mProcessMap.getProcess(pid); mVrController.setVrThreadLocked(tid, pid, wpc); } } @@ -4659,7 +4659,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { enforceSystemHasVrFeature(); synchronized (mGlobalLock) { final int pid = Binder.getCallingPid(); - final WindowProcessController proc = mPidMap.get(pid); + final WindowProcessController proc = mProcessMap.getProcess(pid); mVrController.setPersistentVrThreadLocked(tid, pid, proc); } } @@ -5204,9 +5204,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mH.sendMessage(msg); } - for (int i = mPidMap.size() - 1; i >= 0; i--) { - final int pid = mPidMap.keyAt(i); - final WindowProcessController app = mPidMap.get(pid); + SparseArray<WindowProcessController> pidMap = mProcessMap.getPidMap(); + for (int i = pidMap.size() - 1; i >= 0; i--) { + final int pid = pidMap.keyAt(i); + final WindowProcessController app = pidMap.get(pid); if (DEBUG_CONFIGURATION) { Slog.v(TAG_CONFIGURATION, "Update process config of " + app.mName + " to new config " + configCopy); @@ -5859,7 +5860,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } WindowProcessController getProcessController(int pid, int uid) { - final WindowProcessController proc = mPidMap.get(pid); + final WindowProcessController proc = mProcessMap.getProcess(pid); if (proc == null) return null; if (UserHandle.isApp(uid) && proc.mUid == uid) { return proc; @@ -5872,8 +5873,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } boolean isUidForeground(int uid) { - return (getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) - || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); + // A uid is considered to be foreground if it has a visible non-toast window. + return mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); } boolean isDeviceOwner(int uid) { @@ -6423,14 +6424,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void onProcessMapped(int pid, WindowProcessController proc) { synchronized (mGlobalLock) { - mPidMap.put(pid, proc); + mProcessMap.put(pid, proc); } } @Override public void onProcessUnMapped(int pid) { synchronized (mGlobalLock) { - mPidMap.remove(pid); + mProcessMap.remove(pid); } } @@ -6480,9 +6481,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public void onImeWindowSetOnDisplay(final int pid, final int displayId) { - // Update display configuration for IME process only when Single-client IME window - // moving to another display. - if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return; + // Don't update process-level configuration for Multi-Client IME process since other + // IMEs on other displays will also receive this configuration change due to IME + // services use the same application config/context. + if (InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return; if (pid == MY_PID || pid < 0) { if (DEBUG_CONFIGURATION) { @@ -6502,7 +6504,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } return; } - final WindowProcessController process = mPidMap.get(pid); + final WindowProcessController process = mProcessMap.getProcess(pid); if (process == null) { if (DEBUG_CONFIGURATION) { Slog.w(TAG, "Trying to update display configuration for invalid " @@ -6695,7 +6697,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Only allow this from foreground processes, so that background // applications can't abuse it to prevent system UI from being shown. if (uid >= FIRST_APPLICATION_UID) { - final WindowProcessController proc = mPidMap.get(pid); + final WindowProcessController proc = mProcessMap.getProcess(pid); if (!proc.isPerceptible()) { Slog.w(TAG, "Ignoring closeSystemDialogs " + reason + " from background process " + proc); diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index c8f8e82bdb18..104805fba308 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -48,6 +48,7 @@ import android.os.Message; import android.os.RemoteException; import android.util.AtomicFile; import android.util.Slog; +import android.util.SparseArray; import android.util.Xml; public final class CompatModePackages { @@ -324,8 +325,9 @@ public final class CompatModePackages { ActivityRecord starting = stack.restartPackage(packageName); // Tell all processes that loaded this package about the change. - for (int i = mService.mPidMap.size() - 1; i >= 0; i--) { - final WindowProcessController app = mService.mPidMap.valueAt(i); + SparseArray<WindowProcessController> pidMap = mService.mProcessMap.getPidMap(); + for (int i = pidMap.size() - 1; i >= 0; i--) { + final WindowProcessController app = pidMap.valueAt(i); if (!app.mPkgList.contains(packageName)) { continue; } diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index 4bd8cab05700..a7a793fa8d34 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -41,7 +41,7 @@ class Dimmer { private static final int DEFAULT_DIM_ANIM_DURATION = 200; private class DimAnimatable implements SurfaceAnimator.Animatable { - private final SurfaceControl mDimLayer; + private SurfaceControl mDimLayer; private DimAnimatable(SurfaceControl dimLayer) { mDimLayer = dimLayer; @@ -100,6 +100,11 @@ class Dimmer { // See getSurfaceWidth() above for explanation. return mHost.getSurfaceHeight(); } + + void removeSurface() { + getPendingTransaction().remove(mDimLayer); + mDimLayer = null; + } } @VisibleForTesting @@ -129,8 +134,7 @@ class Dimmer { final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer); mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, () -> { if (!mDimming) { - dimAnimatable.getPendingTransaction().remove(mDimLayer); - mDimLayer = null; + dimAnimatable.removeSurface(); } }, mHost.mWmService); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 1934e2508c9b..bd874ba786ed 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -28,6 +28,7 @@ import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.InsetsState.TYPE_TOP_GESTURES; import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT; +import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; @@ -1230,7 +1231,7 @@ public class DisplayPolicy { final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0; if (layoutInScreenAndInsetDecor && !screenDecor) { - if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) { + if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) { outFrame.set(displayFrames.mUnrestricted); } else { outFrame.set(displayFrames.mRestricted); @@ -1290,7 +1291,7 @@ public class DisplayPolicy { && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT; if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || forceWindowDrawsBarBackgrounds) { - impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; } return impliedFlags; @@ -1722,6 +1723,22 @@ public class DisplayPolicy { of.set(displayFrames.mDock); df.set(displayFrames.mDock); } else { + + // In case we forced the window to draw behind the navigation bar, restrict df/of to + // DF.RestrictedOverscan to simulate old compat behavior. + Rect parentDisplayFrame = attached.getDisplayFrameLw(); + Rect parentOverscan = attached.getOverscanFrameLw(); + final WindowManager.LayoutParams attachedAttrs = attached.mAttrs; + if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0 + && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0 + && (attachedAttrs.systemUiVisibility + & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) { + parentOverscan = new Rect(parentOverscan); + parentOverscan.intersect(displayFrames.mRestrictedOverscan); + parentDisplayFrame = new Rect(parentDisplayFrame); + parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan); + } + // The effective display frame of the attached window depends on whether it is taking // care of insetting its content. If not, we need to use the parent's content frame so // that the entire window is positioned within that content. Otherwise we can use the @@ -1733,7 +1750,7 @@ public class DisplayPolicy { // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag. // Otherwise, use the overscan frame. cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0 - ? attached.getContentFrameLw() : attached.getOverscanFrameLw()); + ? attached.getContentFrameLw() : parentOverscan); } else { // If the window is resizing, then we want to base the content frame on our attached // content frame to resize...however, things can be tricky if the attached window is @@ -1747,8 +1764,8 @@ public class DisplayPolicy { cf.intersectUnchecked(displayFrames.mContent); } } - df.set(insetDecors ? attached.getDisplayFrameLw() : cf); - of.set(insetDecors ? attached.getOverscanFrameLw() : cf); + df.set(insetDecors ? parentDisplayFrame : cf); + of.set(insetDecors ? parentOverscan : cf); vf.set(attached.getVisibleFrameLw()); } // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be @@ -1956,7 +1973,7 @@ public class DisplayPolicy { of.set(displayFrames.mOverscan); df.set(displayFrames.mOverscan); pf.set(displayFrames.mOverscan); - } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 + } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW || type == TYPE_VOLUME_OVERLAY)) { // Asking for layout as if the nav bar is hidden, lets the application @@ -2006,7 +2023,7 @@ public class DisplayPolicy { } } else if (layoutInScreen || (sysUiFl & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) { + | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) { if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN"); // A window that has requested to fill the entire screen just @@ -2051,7 +2068,7 @@ public class DisplayPolicy { of.set(displayFrames.mOverscan); df.set(displayFrames.mOverscan); pf.set(displayFrames.mOverscan); - } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 + } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 && (type == TYPE_STATUS_BAR || type == TYPE_TOAST || type == TYPE_DOCK_DIVIDER diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java index 3d20501222b6..d774dc3fd2f1 100644 --- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java +++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java @@ -90,8 +90,6 @@ public class ImmersiveModeConfirmation { mShowDelayMs = getNavBarExitDuration() * 3; mPanicThresholdMs = context.getResources() .getInteger(R.integer.config_immersive_mode_confirmation_panic); - mWindowManager = (WindowManager) - mContext.getSystemService(Context.WINDOW_SERVICE); mVrModeEnabled = vrModeEnabled; } @@ -177,7 +175,7 @@ public class ImmersiveModeConfirmation { private void handleHide() { if (mClingWindow != null) { if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation"); - mWindowManager.removeView(mClingWindow); + getWindowManager().removeView(mClingWindow); mClingWindow = null; } } @@ -275,7 +273,7 @@ public class ImmersiveModeConfirmation { super.onAttachedToWindow(); DisplayMetrics metrics = new DisplayMetrics(); - mWindowManager.getDefaultDisplay().getMetrics(metrics); + getWindowManager().getDefaultDisplay().getMetrics(metrics); float density = metrics.density; getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener); @@ -341,6 +339,19 @@ public class ImmersiveModeConfirmation { } } + /** + * DO HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD + * The reason why we add this method is to avoid the deadlock of WMG->WMS and WMS->WMG + * when ImmersiveModeConfirmation object is created. + */ + private WindowManager getWindowManager() { + if (mWindowManager == null) { + mWindowManager = (WindowManager) + mContext.getSystemService(Context.WINDOW_SERVICE); + } + return mWindowManager; + } + private void handleShow() { if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation"); @@ -352,7 +363,7 @@ public class ImmersiveModeConfirmation { // show the confirmation WindowManager.LayoutParams lp = getClingWindowLayoutParams(); - mWindowManager.addView(mClingWindow, lp); + getWindowManager().addView(mClingWindow, lp); } private final Runnable mConfirm = new Runnable() { diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index d6c7b21e16b2..7dcbedf811c2 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -60,7 +60,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.text.TextUtils; @@ -185,7 +184,6 @@ class RecentTasks { // front. Newly created tasks, or tasks that are removed from the list will continue to change // the list. This does not affect affiliated tasks. private boolean mFreezeTaskListReordering; - private long mFreezeTaskListReorderingTime; private long mFreezeTaskListTimeoutMs = FREEZE_TASK_LIST_TIMEOUT_MS; // Mainly to avoid object recreation on multiple calls. @@ -220,6 +218,9 @@ class RecentTasks { } }; + private final Runnable mResetFreezeTaskListOnTimeoutRunnable = + this::resetFreezeTaskListReorderingOnTimeout; + @VisibleForTesting RecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) { mService = service; @@ -255,8 +256,7 @@ class RecentTasks { } @VisibleForTesting - void setFreezeTaskListTimeoutParams(long reorderingTime, long timeoutMs) { - mFreezeTaskListReorderingTime = reorderingTime; + void setFreezeTaskListTimeout(long timeoutMs) { mFreezeTaskListTimeoutMs = timeoutMs; } @@ -272,7 +272,8 @@ class RecentTasks { // Always update the reordering time when this is called to ensure that the timeout // is reset mFreezeTaskListReordering = true; - mFreezeTaskListReorderingTime = SystemClock.elapsedRealtime(); + mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable); + mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, mFreezeTaskListTimeoutMs); } /** @@ -286,6 +287,7 @@ class RecentTasks { // Once we end freezing the task list, reset the existing task order to the stable state mFreezeTaskListReordering = false; + mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable); // If the top task is provided, then restore the top task to the front of the list if (topTask != null) { @@ -295,6 +297,8 @@ class RecentTasks { // Resume trimming tasks trimInactiveRecentTasks(); + + mService.getTaskChangeNotificationController().notifyTaskStackChanged(); } /** @@ -302,13 +306,8 @@ class RecentTasks { * before we need to iterate the task list in order (either for purposes of returning the list * to SystemUI or if we need to trim tasks in order) */ + @VisibleForTesting void resetFreezeTaskListReorderingOnTimeout() { - // Unfreeze the recent task list if the time heuristic has passed - if (mFreezeTaskListReorderingTime - > (SystemClock.elapsedRealtime() - mFreezeTaskListTimeoutMs)) { - return; - } - final ActivityStack focusedStack = mService.getTopDisplayFocusedStack(); final TaskRecord topTask = focusedStack != null ? focusedStack.topTask() @@ -875,9 +874,6 @@ class RecentTasks { final Set<Integer> includedUsers = getProfileIds(userId); includedUsers.add(Integer.valueOf(userId)); - // Check if the frozen task list has timed out - resetFreezeTaskListReorderingOnTimeout(); - final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>(); final int size = mTasks.size(); int numVisibleTasks = 0; @@ -1654,8 +1650,8 @@ class RecentTasks { pw.println("mRecentsUid=" + mRecentsUid); pw.println("mRecentsComponent=" + mRecentsComponent); pw.println("mFreezeTaskListReordering=" + mFreezeTaskListReordering); - pw.println("mFreezeTaskListReorderingTime (time since)=" - + (SystemClock.elapsedRealtime() - mFreezeTaskListReorderingTime) + "ms"); + pw.println("mFreezeTaskListReorderingPendingTimeout=" + + mService.mH.hasCallbacks(mResetFreezeTaskListOnTimeoutRunnable)); if (mTasks.isEmpty()) { return; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 1ca31f127b0d..9f4232400221 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -22,6 +22,7 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; @@ -312,11 +313,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> /** * Returns true if the callingUid has any non-toast window currently visible to the user. + * Also ignores TYPE_APPLICATION_STARTING, since those windows don't belong to apps. */ boolean isAnyNonToastWindowVisibleForUid(int callingUid) { - return forAllWindows(w -> { - return w.getOwningUid() == callingUid && w.isVisible() && w.mAttrs.type != TYPE_TOAST; - }, true /* traverseTopToBottom */); + return forAllWindows(w -> + w.getOwningUid() == callingUid && w.mAttrs.type != TYPE_TOAST + && w.mAttrs.type != TYPE_APPLICATION_STARTING && w.isVisibleNow(), + true /* traverseTopToBottom */); } /** diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 33d952e80a6b..b3b41b733cdb 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -286,8 +286,12 @@ class SurfaceAnimator { final boolean destroy = mLeash != null && surface != null && parent != null; if (destroy) { if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent"); - t.reparent(surface, parent); - scheduleAnim = true; + // We shouldn't really need these isValid checks but we do + // b/130364451 + if (surface.isValid() && parent.isValid()) { + t.reparent(surface, parent); + scheduleAnim = true; + } } mService.mAnimationTransferMap.remove(mAnimation); if (mLeash != null && destroyLeash) { diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 33561d3a41d6..eb919eb00f0c 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -44,6 +44,7 @@ import android.app.IApplicationThread; import android.app.ProfilerInfo; import android.app.servertransaction.ConfigurationChangeItem; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.os.Message; @@ -371,16 +372,37 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio mAllowBackgroundActivityStarts = allowBackgroundActivityStarts; } - public boolean areBackgroundActivityStartsAllowed() { - return mAllowBackgroundActivityStarts; + boolean areBackgroundActivityStartsAllowed() { + // allow if the whitelisting flag was explicitly set + if (mAllowBackgroundActivityStarts) { + return true; + } + // allow if the proc is instrumenting with background activity starts privs + if (mInstrumentingWithBackgroundActivityStartPrivileges) { + return true; + } + // allow if the caller has an activity in any foreground task + if (hasActivityInVisibleTask()) { + return true; + } + // allow if the caller is bound by a UID that's currently foreground + if (isBoundByForegroundUid()) { + return true; + } + return false; } - public void setBoundClientUids(ArraySet<Integer> boundClientUids) { - mBoundClientUids = boundClientUids; + private boolean isBoundByForegroundUid() { + for (int i = mBoundClientUids.size() - 1; i >= 0; --i) { + if (mAtm.isUidForeground(mBoundClientUids.valueAt(i))) { + return true; + } + } + return false; } - public ArraySet<Integer> getBoundClientUids() { - return mBoundClientUids; + public void setBoundClientUids(ArraySet<Integer> boundClientUids) { + mBoundClientUids = boundClientUids; } public void setInstrumenting(boolean instrumenting, @@ -393,14 +415,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return mInstrumenting; } - /** - * @return true if the instrumentation was started by a holder of - * START_ACTIVITIES_FROM_BACKGROUND permission - */ - boolean isInstrumentingWithBackgroundActivityStartPrivileges() { - return mInstrumentingWithBackgroundActivityStartPrivileges; - } - public void setPerceptible(boolean perceptible) { mPerceptible = perceptible; } @@ -486,7 +500,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } - boolean hasActivityInVisibleTask() { + private boolean hasActivityInVisibleTask() { for (int i = mActivities.size() - 1; i >= 0; --i) { TaskRecord task = mActivities.get(i).getTaskRecord(); if (task == null) { @@ -771,13 +785,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio WindowProcessListener::clearProfilerIfNeeded, mListener)); } - void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru, - boolean activityChange, boolean updateOomAdj) { + void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange, + boolean updateOomAdj) { if (mListener == null) return; // Posting on handler so WM lock isn't held when we call into AM. final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo, - mListener, updateServiceConnectionActivities, updateLru, activityChange, - updateOomAdj); + mListener, updateServiceConnectionActivities, activityChange, updateOomAdj); mAtm.mH.sendMessage(m); } @@ -801,53 +814,44 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return mListener == null ? false : mListener.isRemoved(); } - void clearWaitingToKill() { - if (mListener == null) return; - // Posting on handler so WM lock isn't held when we call into AM. - final Message m = PooledLambda.obtainMessage( - WindowProcessListener::clearWaitingToKill, mListener); - mAtm.mH.sendMessage(m); + private boolean shouldSetProfileProc() { + return mAtm.mProfileApp != null && mAtm.mProfileApp.equals(mName) + && (mAtm.mProfileProc == null || mAtm.mProfileProc == this); } - void addPackage(String pkg, long versionCode) { - if (mListener == null) return; - // Posting on handler so WM lock isn't held when we call into AM. - final Message m = PooledLambda.obtainMessage( - WindowProcessListener::addPackage, mListener, pkg, versionCode); - mAtm.mH.sendMessage(m); - } - - ProfilerInfo onStartActivity(int topProcessState) { - ProfilerInfo profilerInfo = null; - boolean setProfileProc = false; - if (mAtm.mProfileApp != null - && mAtm.mProfileApp.equals(mName)) { - if (mAtm.mProfileProc == null || mAtm.mProfileProc == this) { - setProfileProc = true; - final ProfilerInfo profilerInfoSvc = mAtm.mProfilerInfo; - if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) { - if (profilerInfoSvc.profileFd != null) { - try { - profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup(); - } catch (IOException e) { - profilerInfoSvc.closeFd(); - } - } - - profilerInfo = new ProfilerInfo(profilerInfoSvc); - } + ProfilerInfo createProfilerInfoIfNeeded() { + final ProfilerInfo currentProfilerInfo = mAtm.mProfilerInfo; + if (currentProfilerInfo == null || currentProfilerInfo.profileFile == null + || !shouldSetProfileProc()) { + return null; + } + if (currentProfilerInfo.profileFd != null) { + try { + currentProfilerInfo.profileFd = currentProfilerInfo.profileFd.dup(); + } catch (IOException e) { + currentProfilerInfo.closeFd(); } } + return new ProfilerInfo(currentProfilerInfo); + } - - if (mListener != null) { - // Posting on handler so WM lock isn't held when we call into AM. - final Message m = PooledLambda.obtainMessage(WindowProcessListener::onStartActivity, - mListener, topProcessState, setProfileProc); - mAtm.mH.sendMessage(m); + void onStartActivity(int topProcessState, ActivityInfo info) { + if (mListener == null) return; + String packageName = null; + if ((info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0 + || !"android".equals(info.packageName)) { + // Don't add this if it is a platform component that is marked to run in multiple + // processes, because this is actually part of the framework so doesn't make sense + // to track as a separate apk in the process. + packageName = info.packageName; } - - return profilerInfo; + // Posting the message at the front of queue so WM lock isn't held when we call into AM, + // and the process state of starting activity can be updated quicker which will give it a + // higher scheduling group. + final Message m = PooledLambda.obtainMessage(WindowProcessListener::onStartActivity, + mListener, topProcessState, shouldSetProfileProc(), packageName, + info.applicationInfo.longVersionCode); + mAtm.mH.sendMessageAtFrontOfQueue(m); } public void appDied() { diff --git a/services/core/java/com/android/server/wm/WindowProcessControllerMap.java b/services/core/java/com/android/server/wm/WindowProcessControllerMap.java new file mode 100644 index 000000000000..2767972f7ea0 --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowProcessControllerMap.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import android.util.ArraySet; +import android.util.SparseArray; + +import java.util.Map; +import java.util.HashMap; + +final class WindowProcessControllerMap { + + /** All processes we currently have running mapped by pid */ + private final SparseArray<WindowProcessController> mPidMap = new SparseArray<>(); + /** All processes we currently have running mapped by uid */ + private final Map<Integer, ArraySet<WindowProcessController>> mUidMap = new HashMap<>(); + + /** Retrieves a currently running process for pid. */ + WindowProcessController getProcess(int pid) { + return mPidMap.get(pid); + } + + /** Retrieves all currently running processes for uid. */ + ArraySet<WindowProcessController> getProcesses(int uid) { + return mUidMap.get(uid); + } + + SparseArray<WindowProcessController> getPidMap() { + return mPidMap; + } + + void put(int pid, WindowProcessController proc) { + // if there is a process for this pid already in mPidMap it'll get replaced automagically, + // but we actually need to remove it from mUidMap too before adding the new one + final WindowProcessController prevProc = mPidMap.get(pid); + if (prevProc != null) { + removeProcessFromUidMap(prevProc); + } + // put process into mPidMap + mPidMap.put(pid, proc); + // put process into mUidMap + final int uid = proc.mUid; + ArraySet<WindowProcessController> procSet = mUidMap.getOrDefault(uid, + new ArraySet<WindowProcessController>()); + procSet.add(proc); + mUidMap.put(uid, procSet); + } + + void remove(int pid) { + final WindowProcessController proc = mPidMap.get(pid); + if (proc != null) { + // remove process from mPidMap + mPidMap.remove(pid); + // remove process from mUidMap + removeProcessFromUidMap(proc); + } + } + + private void removeProcessFromUidMap(WindowProcessController proc) { + if (proc == null) { + return; + } + final int uid = proc.mUid; + ArraySet<WindowProcessController> procSet = mUidMap.get(uid); + if (procSet != null) { + procSet.remove(proc); + if (procSet.isEmpty()) { + mUidMap.remove(uid); + } + } + } +} diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java index d732e4e8f341..527d54a40d03 100644 --- a/services/core/java/com/android/server/wm/WindowProcessListener.java +++ b/services/core/java/com/android/server/wm/WindowProcessListener.java @@ -41,8 +41,8 @@ public interface WindowProcessListener { void setPendingUiCleanAndForceProcessStateUpTo(int newState); /** Update the process information. */ - void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru, - boolean activityChange, boolean updateOomAdj); + void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange, + boolean updateOomAdj); /** * Returns true if the process is removed and we should completely clean up the related records @@ -53,14 +53,9 @@ public interface WindowProcessListener { /** Returns the total time (in milliseconds) spent executing in both user and system code. */ long getCpuTime(); - /** Clears the waiting to kill reason for this process. */ - void clearWaitingToKill(); - - /** Adds the package to the process. */ - void addPackage(String pkg, long versionCode); - /** Called when we are in the process on starting an activity. */ - void onStartActivity(int topProcessState, boolean setProfileProc); + void onStartActivity(int topProcessState, boolean setProfileProc, String packageName, + long versionCode); /** App died :(...oh well */ void appDied(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d990e6c6c24b..8e18683d3e76 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1305,7 +1305,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void onDisplayChanged(DisplayContent dc) { super.onDisplayChanged(dc); // Window was not laid out for this display yet, so make sure mLayoutSeq does not match. - if (dc != null) { + if (dc != null && mInputWindowHandle.displayId != dc.getDisplayId()) { mLayoutSeq = dc.mLayoutSeq - 1; mInputWindowHandle.displayId = dc.getDisplayId(); } diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 73e9bf0e1202..b470ec7a00ba 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1693,7 +1693,7 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass // 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement // 1.0@IGnss is paired with 1.0@IGnssMeasurement gnssMeasurementIface = nullptr; - if (gnssHal_V2_0 != nullptr && gnssMeasurementIface == nullptr) { + if (gnssHal_V2_0 != nullptr) { auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0(); if (!gnssMeasurement.isOk()) { ALOGD("Unable to get a handle to GnssMeasurement_V2_0"); @@ -1730,6 +1730,10 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass } } + // Allow all causal combinations between IGnss.hal and IGnssDebug.hal. That means, + // 2.0@IGnss can be paired with {1.0, 2.0}@IGnssDebug + // 1.0@IGnss is paired with 1.0@IGnssDebug + gnssDebugIface = nullptr; if (gnssHal_V2_0 != nullptr) { auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0(); if (!gnssDebug.isOk()) { @@ -1738,7 +1742,8 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass gnssDebugIface_V2_0 = gnssDebug; gnssDebugIface = gnssDebugIface_V2_0; } - } else { + } + if (gnssDebugIface == nullptr) { auto gnssDebug = gnssHal->getExtensionGnssDebug(); if (!gnssDebug.isOk()) { ALOGD("Unable to get a handle to GnssDebug"); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java index d5cfab960171..5acf83aeb890 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java @@ -194,8 +194,17 @@ class AbUpdateInstaller extends UpdateInstaller { } UpdateEngine updateEngine = buildBoundUpdateEngine(); - updateEngine.applyPayload( - updatePath, mOffsetForUpdate, mSizeForUpdate, headerKeyValuePairs); + try { + updateEngine.applyPayload( + updatePath, mOffsetForUpdate, mSizeForUpdate, headerKeyValuePairs); + } catch (Exception e) { + // Prevent an automatic restart when an update is already being processed + // (http://b/124106342). + Log.w(UpdateInstaller.TAG, "Failed to install update from file.", e); + notifyCallbackOnError( + InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN, + "Failed to install update from file."); + } } private boolean updateStateForPayload() throws IOException { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 0cd730b68c72..2a2de7796424 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -32,7 +32,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; @@ -1248,11 +1247,6 @@ public final class SystemServer { mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS); traceEnd(); - // NOTE: ClipboardService indirectly depends on IntelligenceService - traceBeginAndSlog("StartClipboardService"); - mSystemServiceManager.startService(ClipboardService.class); - traceEnd(); - traceBeginAndSlog("InitNetworkStackClient"); try { NetworkStackClient.getInstance().init(); @@ -1887,6 +1881,11 @@ public final class SystemServer { traceEnd(); } + // NOTE: ClipboardService depends on ContentCapture and Autofill + traceBeginAndSlog("StartClipboardService"); + mSystemServiceManager.startService(ClipboardService.class); + traceEnd(); + traceBeginAndSlog("AppServiceManager"); mSystemServiceManager.startService(AppBindingService.Lifecycle.class); traceEnd(); diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java index 339607bbc73d..59aea21f46c8 100644 --- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java +++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java @@ -36,6 +36,7 @@ import android.system.StructTimeval; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.TrafficStatsConstants; import libcore.io.IoBridge; @@ -586,7 +587,8 @@ public class RouterAdvertisementDaemon { private boolean createSocket() { final int SEND_TIMEOUT_MS = 300; - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NEIGHBOR); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_NEIGHBOR); try { mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); // Setting SNDTIMEO is purely for defensive purposes. diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml index c9aa63153a5d..32d7d026ff10 100644 --- a/services/tests/mockingservicestests/AndroidManifest.xml +++ b/services/tests/mockingservicestests/AndroidManifest.xml @@ -17,6 +17,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.frameworks.mockingservicestests"> + <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> + <uses-permission android:name="android.permission.HARDWARE_TEST"/> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <application android:testOnly="true" diff --git a/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java index fc74c972ed83..73b3b8b1ce3c 100644 --- a/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java @@ -16,87 +16,119 @@ package com.android.server.display.color; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR; import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; + import android.hardware.display.ColorDisplayManager; import android.os.SystemProperties; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; @RunWith(AndroidJUnit4.class) public class DisplayTransformManagerTest { + private MockitoSession mSession; private DisplayTransformManager mDtm; private float[] mNightDisplayMatrix; + private HashMap<String, String> mSystemProperties; @Before public void setUp() { mDtm = new DisplayTransformManager(); mNightDisplayMatrix = mDtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY); - SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, null); - SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, null); + mSession = ExtendedMockito.mockitoSession() + .initMocks(this) + .strictness(Strictness.LENIENT) + .spyStatic(SystemProperties.class) + .startMocking(); + mSystemProperties = new HashMap<>(); + + doAnswer((Answer<Void>) invocationOnMock -> { + mSystemProperties.put(invocationOnMock.getArgument(0), + invocationOnMock.getArgument(1)); + return null; + } + ).when(() -> SystemProperties.set(anyString(), any())); + } + + @After + public void tearDown() throws Exception { + mSession.finishMocking(); + mSystemProperties.clear(); } @Test public void setColorMode_natural() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("0" /* managed */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_boosted() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("0" /* managed */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.1" /* boosted */); } @Test public void setColorMode_saturated() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("1" /* unmanaged */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_automatic() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("2" /* enhanced */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_vendor() { mDtm.setColorMode(0x100, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo(Integer.toString(0x100) /* pass-through */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) - .isEqualTo("1.0" /* default */); + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) + .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_outOfBounds() { mDtm.setColorMode(0x50, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) - .isEqualTo("" /* default */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) - .isEqualTo("" /* default */); + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) + .isEqualTo(null); + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) + .isEqualTo(null); } } diff --git a/services/tests/servicestests/src/com/android/server/ThreadPriorityBoosterTest.java b/services/tests/servicestests/src/com/android/server/ThreadPriorityBoosterTest.java new file mode 100644 index 000000000000..b4e9ff77744c --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/ThreadPriorityBoosterTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import static android.os.Process.getThreadPriority; +import static android.os.Process.myTid; +import static android.os.Process.setThreadPriority; + +import static org.junit.Assert.assertEquals; + +import android.os.Process; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Tests for {@link ThreadPriorityBooster}. + * Build/Install/Run: + * atest FrameworksServicesTests:ThreadPriorityBoosterTest + */ +@SmallTest +@Presubmit +public class ThreadPriorityBoosterTest { + private static final int PRIORITY_BOOST = Process.THREAD_PRIORITY_FOREGROUND; + private static final int PRIORITY_BOOST_MORE = Process.THREAD_PRIORITY_DISPLAY; + + private final ThreadPriorityBooster mBooster = new ThreadPriorityBooster(PRIORITY_BOOST, + 0 /* lockGuardIndex */); + + @Test + public void testThreadPriorityBooster() { + joinNewThread(() -> { + final int origPriority = Process.THREAD_PRIORITY_DEFAULT; + setThreadPriority(origPriority); + + boost(() -> { + assertThreadPriority(PRIORITY_BOOST); + boost(() -> { + // Inside the boost region, the priority should also apply to current thread. + mBooster.setBoostToPriority(PRIORITY_BOOST_MORE); + assertThreadPriority(PRIORITY_BOOST_MORE); + }); + // It is still in the boost region so the set priority should be kept. + assertThreadPriority(PRIORITY_BOOST_MORE); + + joinNewThread(() -> boost(() -> assertThreadPriority(PRIORITY_BOOST_MORE))); + }); + // The priority should be restored after leaving the boost region. + assertThreadPriority(origPriority); + + // It doesn't apply to current thread because outside of the boost region, but the boost + // in other threads will use the set priority. + mBooster.setBoostToPriority(PRIORITY_BOOST); + joinNewThread(() -> boost(() -> assertThreadPriority(PRIORITY_BOOST))); + + assertThreadPriority(origPriority); + }); + } + + private static void assertThreadPriority(int expectedPriority) { + assertEquals(expectedPriority, getThreadPriority(myTid())); + } + + private static void joinNewThread(Runnable action) { + final Thread thread = new Thread(action); + thread.start(); + try { + thread.join(); + } catch (InterruptedException ignored) { + } + } + + private void boost(Runnable action) { + try { + mBooster.boost(); + action.run(); + } finally { + mBooster.reset(); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java index 2cba9d022866..2977414fb302 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java @@ -17,6 +17,7 @@ package com.android.server.accessibility; import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_HOVER_MOVE; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER; @@ -116,6 +117,7 @@ public class MotionEventInjectorTest { MotionEvent mClickDownEvent; MotionEvent mClickUpEvent; + MotionEvent mHoverMoveEvent; ArgumentCaptor<MotionEvent> mCaptor1 = ArgumentCaptor.forClass(MotionEvent.class); ArgumentCaptor<MotionEvent> mCaptor2 = ArgumentCaptor.forClass(MotionEvent.class); @@ -152,6 +154,10 @@ public class MotionEventInjectorTest { CLICK_POINT.y, 0); mClickUpEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); + mHoverMoveEvent = MotionEvent.obtain(0, 0, ACTION_HOVER_MOVE, CLICK_POINT.x, CLICK_POINT.y, + 0); + mHoverMoveEvent.setSource(InputDevice.SOURCE_MOUSE); + mIsLineStart = allOf(IS_ACTION_DOWN, isAtPoint(LINE_START), hasStandardInitialization(), hasTimeFromDown(0)); mIsLineMiddle = allOf(IS_ACTION_MOVE, isAtPoint(LINE_END), hasStandardInitialization(), @@ -301,6 +307,23 @@ public class MotionEventInjectorTest { } @Test + public void + testOnMotionEvents_fromMouseWithInjectedGestureInProgress_shouldNotCancelAndPassReal() + throws RemoteException { + EventStreamTransformation next = attachMockNext(mMotionEventInjector); + injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); + mMessageCapturingHandler.sendOneMessage(); // Send a motion event + mMotionEventInjector.onMotionEvent(mHoverMoveEvent, mHoverMoveEvent, 0); + mMessageCapturingHandler.sendAllMessages(); + + verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); + assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); + assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle); + assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd); + verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); + } + + @Test public void testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 4e21fd0cd0de..3df6976a2cae 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -322,7 +322,8 @@ public class ActivityManagerServiceTest { ApplicationInfo appInfo = new ApplicationInfo(); appInfo.processName = "com.android.test.app"; appInfo.uid = 10000; - final IsolatedUidRange range = allocator.getOrCreateIsolatedUidRangeLocked(appInfo); + final IsolatedUidRange range = allocator.getOrCreateIsolatedUidRangeLocked( + appInfo.processName, appInfo.uid); validateAppZygoteIsolatedUidRange(range); verifyIsolatedUidAllocator(range); @@ -330,7 +331,8 @@ public class ActivityManagerServiceTest { ApplicationInfo appInfo2 = new ApplicationInfo(); appInfo2.processName = "com.android.test.app2"; appInfo2.uid = 10001; - IsolatedUidRange range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2); + IsolatedUidRange range2 = allocator.getOrCreateIsolatedUidRangeLocked( + appInfo2.processName, appInfo2.uid); validateAppZygoteIsolatedUidRange(range2); verifyIsolatedUidAllocator(range2); @@ -339,7 +341,7 @@ public class ActivityManagerServiceTest { // Free range, reallocate and verify allocator.freeUidRangeLocked(appInfo2); - range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2); + range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2.processName, appInfo2.uid); validateAppZygoteIsolatedUidRange(range2); verifyUidRangesNoOverlap(range, range2); verifyIsolatedUidAllocator(range2); @@ -354,7 +356,8 @@ public class ActivityManagerServiceTest { appInfo = new ApplicationInfo(); appInfo.uid = 10000 + i; appInfo.processName = "com.android.test.app" + Integer.toString(i); - IsolatedUidRange uidRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo); + IsolatedUidRange uidRange = allocator.getOrCreateIsolatedUidRangeLocked( + appInfo.processName, appInfo.uid); validateAppZygoteIsolatedUidRange(uidRange); verifyIsolatedUidAllocator(uidRange); } @@ -363,7 +366,8 @@ public class ActivityManagerServiceTest { appInfo = new ApplicationInfo(); appInfo.uid = 9000; appInfo.processName = "com.android.test.app.failed"; - IsolatedUidRange failedRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo); + IsolatedUidRange failedRange = allocator.getOrCreateIsolatedUidRangeLocked( + appInfo.processName, appInfo.uid); assertNull(failedRange); } diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java index 36f84d053817..c42a71858f26 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -15,8 +15,11 @@ */ package com.android.server.appop; +import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; +import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_ERRORED; +import static android.app.AppOpsManager.MODE_FOREGROUND; import static android.app.AppOpsManager.OP_COARSE_LOCATION; import static android.app.AppOpsManager.OP_READ_SMS; import static android.app.AppOpsManager.OP_WIFI_SCAN; @@ -25,6 +28,7 @@ import static android.app.AppOpsManager.OP_WRITE_SMS; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import android.app.ActivityManager; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; import android.content.Context; @@ -37,6 +41,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.appop.AppOpsService; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -222,6 +227,108 @@ public class AppOpsServiceTest { assertThat(getLoggedOps()).isNull(); } + private void setupProcStateTests() { + // For the location proc state tests + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_FOREGROUND); + mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0; + mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0; + mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0; + } + + @Test + public void testUidProcStateChange_cachedToTopToCached() throws Exception { + setupProcStateTests(); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + // Second time to make sure that settle time is overcome + Thread.sleep(50); + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + } + + @Test + public void testUidProcStateChange_cachedToFgs() throws Exception { + setupProcStateTests(); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + } + + @Test + public void testUidProcStateChange_cachedToFgsLocation() throws Exception { + setupProcStateTests(); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, + PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isEqualTo(MODE_ALLOWED); + } + + @Test + public void testUidProcStateChange_topToFgs() throws Exception { + setupProcStateTests(); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); + // Second time to make sure that settle time is overcome + Thread.sleep(50); + mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + } + + @Test + public void testUidProcStateChange_topToFgsLocationToFgs() throws Exception { + setupProcStateTests(); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); + // Second time to make sure that settle time is overcome + Thread.sleep(50); + mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isEqualTo(MODE_ALLOWED); + + mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); + // Second time to make sure that settle time is overcome + Thread.sleep(50); + mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + .isNotEqualTo(MODE_ALLOWED); + } + private List<PackageOps> getLoggedOps() { return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */); } diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java new file mode 100644 index 000000000000..8426a0bb2c11 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.attention; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.attention.AttentionManagerInternal.AttentionCallbackInternal; +import android.content.ComponentName; +import android.content.Context; +import android.os.IBinder; +import android.os.IPowerManager; +import android.os.PowerManager; +import android.os.RemoteException; +import android.service.attention.IAttentionCallback; +import android.service.attention.IAttentionService; + +import androidx.test.filters.SmallTest; + +import com.android.server.attention.AttentionManagerService.AttentionCheck; +import com.android.server.attention.AttentionManagerService.AttentionHandler; +import com.android.server.attention.AttentionManagerService.UserState; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link com.android.server.attention.AttentionManagerService} + */ +@SmallTest +public class AttentionManagerServiceTest { + private AttentionManagerService mSpyAttentionManager; + private UserState mSpyUserState; + private final int mTimeout = 1000; + @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal; + @Mock private AttentionHandler mMockHandler; + @Mock private IAttentionCallback mMockIAttentionCallback; + @Mock private IPowerManager mMockIPowerManager; + @Mock Context mContext; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + // setup context mock + doReturn(true).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any()); + // setup power manager mock + PowerManager mPowerManager; + doReturn(true).when(mMockIPowerManager).isInteractive(); + mPowerManager = new PowerManager(mContext, mMockIPowerManager, null); + + Object mLock = new Object(); + // setup a spy on attention manager + AttentionManagerService mAttentionManager = new AttentionManagerService( + mContext, + mPowerManager, + mLock, + mMockHandler); + mSpyAttentionManager = Mockito.spy(mAttentionManager); + // setup a spy on user state + ComponentName componentName = new ComponentName("a", "b"); + mSpyAttentionManager.mComponentName = componentName; + UserState mUserState = new UserState(0, + mContext, + mLock, + componentName); + mUserState.mService = new MockIAttentionService(); + mSpyUserState = spy(mUserState); + } + + @Test + public void testCancelAttentionCheck_noCrashWhenNoUserStateLocked() { + mSpyAttentionManager.cancelAttentionCheck(null); + } + + @Test + public void testCancelAttentionCheck_noCrashWhenCallbackMismatched() { + mSpyUserState.mCurrentAttentionCheck = + new AttentionCheck(mMockAttentionCallbackInternal, mMockIAttentionCallback); + doReturn(mSpyUserState).when(mSpyAttentionManager).peekCurrentUserStateLocked(); + mSpyAttentionManager.cancelAttentionCheck(null); + } + + @Test + public void testCancelAttentionCheck_cancelCallbackWhenMatched() { + mSpyUserState.mCurrentAttentionCheck = + new AttentionCheck(mMockAttentionCallbackInternal, mMockIAttentionCallback); + doReturn(mSpyUserState).when(mSpyAttentionManager).peekCurrentUserStateLocked(); + mSpyAttentionManager.cancelAttentionCheck(mMockAttentionCallbackInternal); + verify(mSpyAttentionManager).cancel(any()); + } + + @Test + public void testCheckAttention_returnFalseWhenPowerManagerNotInteract() throws RemoteException { + doReturn(false).when(mMockIPowerManager).isInteractive(); + AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class); + assertThat(mSpyAttentionManager.checkAttention(mTimeout, callback)).isFalse(); + } + + @Test + public void testCheckAttention_callOnSuccess() throws RemoteException { + doReturn(true).when(mSpyAttentionManager).isServiceEnabled(); + doReturn(true).when(mMockIPowerManager).isInteractive(); + doReturn(mSpyUserState).when(mSpyAttentionManager).getOrCreateCurrentUserStateLocked(); + doNothing().when(mSpyAttentionManager).freeIfInactiveLocked(); + + AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class); + mSpyAttentionManager.checkAttention(mTimeout, callback); + verify(callback).onSuccess(anyInt(), anyLong()); + } + + private class MockIAttentionService implements IAttentionService { + public void checkAttention(IAttentionCallback callback) throws RemoteException { + callback.onSuccess(0, 0); + } + public void cancelAttentionCheck(IAttentionCallback callback) { + } + public IBinder asBinder() { + return null; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java index 5de41ea5e7d1..4de00f7b5565 100644 --- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java +++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; import android.attention.AttentionManagerInternal; import android.attention.AttentionManagerInternal.AttentionCallbackInternal; +import android.content.pm.PackageManager; import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.SystemClock; @@ -49,6 +50,8 @@ import org.mockito.MockitoAnnotations; public class AttentionDetectorTest extends AndroidTestCase { @Mock + private PackageManager mPackageManager; + @Mock private AttentionManagerInternal mAttentionManagerInternal; @Mock private Runnable mOnUserAttention; @@ -60,6 +63,9 @@ public class AttentionDetectorTest extends AndroidTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); + when(mPackageManager.getAttentionServicePackageName()).thenReturn("com.google.android.as"); + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_GRANTED); when(mAttentionManagerInternal.checkAttention(anyLong(), any())) .thenReturn(true); mAttentionDetector = new TestableAttentionDetector(); @@ -108,6 +114,27 @@ public class AttentionDetectorTest extends AndroidTestCase { } @Test + public void testOnUserActivity_doesntCheckIfNotSufficientPermissions() { + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_DENIED); + + long when = registerAttention(); + verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any()); + assertThat(mNextDimming).isEqualTo(when); + } + + @Test + public void testOnUserActivity_disablesSettingIfNotSufficientPermissions() { + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_DENIED); + + registerAttention(); + boolean enabled = Settings.System.getIntForUser(getContext().getContentResolver(), + Settings.System.ADAPTIVE_SLEEP, 0, UserHandle.USER_CURRENT) == 1; + assertFalse(enabled); + } + + @Test public void testOnUserActivity_doesntCrashIfNoAttentionService() { mAttentionManagerInternal = null; registerAttention(); @@ -211,6 +238,8 @@ public class AttentionDetectorTest extends AndroidTestCase { TestableAttentionDetector() { super(AttentionDetectorTest.this.mOnUserAttention, new Object()); mAttentionManager = mAttentionManagerInternal; + mPackageManager = AttentionDetectorTest.this.mPackageManager; + mContentResolver = getContext().getContentResolver(); mMaximumExtensionMillis = 10000L; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index 96db38b14ad5..a7bbe6e4cf02 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -87,7 +87,7 @@ public class ActivityStartControllerTests extends ActivityTestsBase { mController.doPendingActivityLaunches(resume); verify(mStarter, times(1)).startResolvedActivity(eq(activity), eq(source), eq(null), - eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null)); + eq(null), eq(startFlags), eq(resume), eq(null), eq(null)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 44aa55d07133..45d52195c5fd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -577,12 +577,27 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_callingUidProcessStateTop_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_realCallingUidProcessStateTop_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, + false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_hasForegroundActivities_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + true, false, false, false, false, false); } /** * This test ensures that supported usecases aren't aborted when background starts are * disallowed. - * The scenarios each have only one condidion that makes them supported. + * The scenarios each have only one condition that makes them supported. */ @Test public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() { @@ -606,26 +621,11 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidProcessStateTop_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false, false); - runAndVerifyBackgroundActivityStartsSubtest( "disallowed_realCallingUidHasVisibleWindow_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1, false, false, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_realCallingUidProcessStateTop_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, - false, false, false, false, false, false); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_hasForegroundActivities_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - true, false, false, false, false, false); - runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callerIsRecents_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index c4009df27c1f..ca3f6846f74d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -52,6 +52,7 @@ import android.view.Display; import android.view.Surface; import android.view.WindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -383,6 +384,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130392471) public void testAddRemoveRace() { // There was once a race condition between adding and removing starting windows for (int i = 0; i < 1000; i++) { diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 329af952c07a..bb574ceed4e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -48,6 +48,7 @@ import android.platform.test.annotations.Presubmit; import android.util.Log; import android.view.IWindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.server.am.AssistDataRequester; @@ -150,6 +151,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 130388718) public void testRequestData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, CALLER_ASSIST_SCREENSHOT_ALLOWED); @@ -250,6 +252,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 130388718) public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, CALLER_ASSIST_SCREENSHOT_ALLOWED); @@ -260,6 +263,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 130388718) public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, !CALLER_ASSIST_SCREENSHOT_ALLOWED); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index af048586b425..3392bc43e568 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -712,7 +712,6 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.add(mTasks.get(4)); // Freeze the list - long freezeTime = SystemClock.elapsedRealtime(); mRecentTasks.setFreezeTaskListReordering(); assertTrue(mRecentTasks.isFreezeTaskListReorderingSet()); @@ -720,13 +719,11 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.add(mTasks.get(2)); mRecentTasks.add(mTasks.get(1)); - // Override the freeze timeout params to simulate the timeout (simulate the freeze at 100ms - // ago with a timeout of 1ms) - mRecentTasks.setFreezeTaskListTimeoutParams(freezeTime - 100, 1); - ActivityStack stack = mTasks.get(2).getStack(); stack.moveToFront("", mTasks.get(2)); doReturn(stack).when(mTestService.mRootActivityContainer).getTopDisplayFocusedStack(); + + // Simulate the reset from the timeout mRecentTasks.resetFreezeTaskListReorderingOnTimeout(); assertFalse(mRecentTasks.isFreezeTaskListReorderingSet()); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 35a8ec37c758..f51ce131b7bc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; @@ -44,14 +45,18 @@ public class RootWindowContainerTests extends WindowTestsBase { private static final int FAKE_CALLING_UID = 667; @Test - public void testIsAnyNonToastWindowVisibleForUid_oneToastOneNonToastBothVisible() { + public void testIsAnyNonToastWindowVisibleForUid_oneToastOneAppStartOneNonToastBothVisible() { final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID); final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID); + final WindowState appStart = createWindow(null, TYPE_APPLICATION_STARTING, "appStarting", + FAKE_CALLING_UID); toastyToast.mHasSurface = true; app.mHasSurface = true; + appStart.mHasSurface = true; - assertTrue(toastyToast.isVisible()); - assertTrue(app.isVisible()); + assertTrue(toastyToast.isVisibleNow()); + assertTrue(app.isVisibleNow()); + assertTrue(appStart.isVisibleNow()); assertTrue(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } @@ -60,7 +65,17 @@ public class RootWindowContainerTests extends WindowTestsBase { final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID); toastyToast.mHasSurface = true; - assertTrue(toastyToast.isVisible()); + assertTrue(toastyToast.isVisibleNow()); + assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); + } + + @Test + public void testIsAnyNonToastWindowVisibleForUid_onlyAppStartingVisible() { + final WindowState appStart = createWindow(null, TYPE_APPLICATION_STARTING, "appStarting", + FAKE_CALLING_UID); + appStart.mHasSurface = true; + + assertTrue(appStart.isVisibleNow()); assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } @@ -69,8 +84,8 @@ public class RootWindowContainerTests extends WindowTestsBase { final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar", FAKE_CALLING_UID); final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID); - assertFalse(topBar.isVisible()); - assertFalse(app.isVisible()); + assertFalse(topBar.isVisibleNow()); + assertFalse(app.isVisibleNow()); assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 9722d2ccce99..62247d889485 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -39,6 +39,7 @@ import android.platform.test.annotations.Presubmit; import android.support.test.uiautomator.UiDevice; import android.text.TextUtils; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.internal.annotations.GuardedBy; @@ -78,6 +79,7 @@ public class TaskStackChangedListenerTest { @Test @Presubmit + @FlakyTest(bugId = 130388819) public void testTaskStackChanged_afterFinish() throws Exception { registerTaskStackChangedListener(new TaskStackListener() { @Override @@ -159,6 +161,7 @@ public class TaskStackChangedListenerTest { */ @Test @Presubmit + @FlakyTest(bugId = 130388819) public void testTaskChangeCallBacks() throws Exception { final Object[] params = new Object[2]; final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index 78fca0f2e6ef..06bcdf8fcadf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -36,6 +36,7 @@ import android.view.Gravity; import android.view.IWindow; import android.view.WindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.utils.WmDisplayCutout; @@ -323,6 +324,7 @@ public class WindowFrameTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130388666) public void testCalculatePolicyCrop() { final FrameTestWindowState w = createWindow(MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; @@ -423,6 +425,7 @@ public class WindowFrameTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130388666) public void testDisplayCutout() { // Regular fullscreen task and window WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT); @@ -446,6 +449,7 @@ public class WindowFrameTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130388666) public void testDisplayCutout_tempDisplayedBounds() { // Regular fullscreen task and window WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java new file mode 100644 index 000000000000..cb7bff3a4f15 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.os.UserHandle; +import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the {@link WindowProcessControllerMap} class. + * + * Build/Install/Run: + * atest WmTests:WindowProcessControllerMapTests + */ +@SmallTest +@Presubmit +public class WindowProcessControllerMapTests extends ActivityTestsBase { + + private static final int FAKE_UID1 = 666; + private static final int FAKE_UID2 = 667; + private static final int FAKE_PID1 = 668; + private static final int FAKE_PID2 = 669; + private static final int FAKE_PID3 = 670; + private static final int FAKE_PID4 = 671; + + private WindowProcessControllerMap mProcessMap; + private WindowProcessController pid1uid1; + private WindowProcessController pid1uid2; + private WindowProcessController pid2uid1; + private WindowProcessController pid3uid1; + private WindowProcessController pid4uid2; + + @Before + public void setUp() throws Exception { + mProcessMap = new WindowProcessControllerMap(); + pid1uid1 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid1", FAKE_UID1, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid1uid1.setPid(FAKE_PID1); + pid1uid2 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid2", FAKE_UID2, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid1uid2.setPid(FAKE_PID1); + pid2uid1 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid2fakeuid1", FAKE_UID1, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid2uid1.setPid(FAKE_PID2); + pid3uid1 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid3fakeuid1", FAKE_UID1, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid3uid1.setPid(FAKE_PID3); + pid4uid2 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid4fakeuid2", FAKE_UID2, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid4uid2.setPid(FAKE_PID4); + } + + @Test + public void testAdditionsAndRemovals() { + // test various additions and removals + mProcessMap.put(FAKE_PID1, pid1uid1); + mProcessMap.put(FAKE_PID2, pid2uid1); + assertEquals(pid1uid1, mProcessMap.getProcess(FAKE_PID1)); + assertEquals(pid2uid1, mProcessMap.getProcess(FAKE_PID2)); + ArraySet<WindowProcessController> uid1processes = mProcessMap.getProcesses(FAKE_UID1); + assertTrue(uid1processes.contains(pid1uid1)); + assertTrue(uid1processes.contains(pid2uid1)); + assertEquals(uid1processes.size(), 2); + + mProcessMap.remove(FAKE_PID2); + mProcessMap.put(FAKE_PID3, pid3uid1); + uid1processes = mProcessMap.getProcesses(FAKE_UID1); + assertTrue(uid1processes.contains(pid1uid1)); + assertFalse(uid1processes.contains(pid2uid1)); + assertTrue(uid1processes.contains(pid3uid1)); + assertEquals(uid1processes.size(), 2); + + mProcessMap.put(FAKE_PID4, pid4uid2); + ArraySet<WindowProcessController> uid2processes = mProcessMap.getProcesses(FAKE_UID2); + assertTrue(uid2processes.contains(pid4uid2)); + assertEquals(uid2processes.size(), 1); + + mProcessMap.remove(FAKE_PID1); + mProcessMap.remove(FAKE_PID3); + assertNull(mProcessMap.getProcesses(FAKE_UID1)); + assertEquals(mProcessMap.getProcess(FAKE_PID4), pid4uid2); + } + + @Test + public void testReplacement() { + // test that replacing a process is handled correctly + mProcessMap.put(FAKE_PID1, pid1uid1); + ArraySet<WindowProcessController> uid1processes = mProcessMap.getProcesses(FAKE_UID1); + assertTrue(uid1processes.contains(pid1uid1)); + assertEquals(uid1processes.size(), 1); + + mProcessMap.put(FAKE_PID1, pid1uid2); + assertNull(mProcessMap.getProcesses(FAKE_UID1)); + ArraySet<WindowProcessController> uid2processes = mProcessMap.getProcesses(FAKE_UID2); + assertTrue(uid2processes.contains(pid1uid2)); + assertEquals(uid2processes.size(), 1); + assertEquals(mProcessMap.getProcess(FAKE_PID1), pid1uid2); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 4f8fe5b10f19..715353e5d980 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -397,7 +397,9 @@ public class WindowStateTests extends WindowTestsBase { app.mLayoutSeq = 1; mDisplayContent.mLayoutSeq = 1; - app.onDisplayChanged(mDisplayContent); + DisplayContent newDisplay = createNewDisplay(); + + app.onDisplayChanged(newDisplay); assertThat(app.mLayoutSeq, not(is(mDisplayContent.mLayoutSeq))); } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 79e6851039ba..5b7d81697c8c 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -1095,6 +1095,14 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser Slog.d(TAG, "Clear notification"); mUsbNotificationId = 0; } + // Not relevant for automotive. + if (mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE) + && id == SystemMessage.NOTE_USB_CHARGING) { + mUsbNotificationId = 0; + return; + } + if (id != 0) { CharSequence title = r.getText(titleRes); PendingIntent pi; diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index cbcd40f15583..ebfa3a15639a 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -41,26 +41,12 @@ import java.util.List; /** * This service is implemented by an app that wishes to provide functionality for managing * phone calls. - * <p> - * There are three types of apps which Telecom can bind to when there exists a live (active or - * incoming) call: - * <ol> - * <li>Default Dialer/Phone app - the default dialer/phone app is one which provides the - * in-call user interface while the device is in a call. A device is bundled with a system - * provided default dialer/phone app. The user may choose a single app to take over this role - * from the system app.</li> - * <li>Default Car-mode Dialer/Phone app - the default car-mode dialer/phone app is one which - * provides the in-call user interface while the device is in a call and the device is in car - * mode. The user may choose a single app to fill this role.</li> - * <li>Call Companion app - a call companion app is one which provides no user interface itself, - * but exposes call information to another display surface, such as a wearable device. The - * user may choose multiple apps to fill this role.</li> - * </ol> - * <p> - * Apps which wish to fulfill one of the above roles use the {@link android.app.role.RoleManager} - * to request that they fill the desired role. - * * <h2>Becoming the Default Phone App</h2> + * The default dialer/phone app is one which provides the in-call user interface while the device is + * in a call. A device is bundled with a system provided default dialer/phone app. The user may + * choose a single app to take over this role from the system app. An app which wishes to fulfill + * one this role uses the {@code android.app.role.RoleManager} to request that they fill the role. + * <p> * An app filling the role of the default phone app provides a user interface while the device is in * a call, and the device is not in car mode. * <p> @@ -193,47 +179,6 @@ import java.util.List; * notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build()); * }</pre> * <p> - * <h2>Becoming the Default Car-mode Phone App</h2> - * An app filling the role of the default car-mode dialer/phone app provides a user interface while - * the device is in a call, and in car mode. See - * {@link android.app.UiModeManager#ACTION_ENTER_CAR_MODE} for more information about car mode. - * When the device is in car mode, Telecom binds to the default car-mode dialer/phone app instead - * of the usual dialer/phone app. - * <p> - * Similar to the requirements for becoming the default dialer/phone app, your app must declare a - * manifest entry for its {@link InCallService} implementation. Your manifest entry should ensure - * the following conditions are met: - * <ul> - * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li> - * <li>Set the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} metadata to - * {@code true}<li> - * <li>Your app must request the permission - * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> - * </ul> - * <p> - * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER} in order to - * become the default (see <a href="#requestRole">above</a> for how to request your app fills this - * role). - * - * <h2>Becoming a Call Companion App</h2> - * An app which fills the companion app role does not directly provide a user interface while the - * device is in a call. Instead, it is typically used to relay information about calls to another - * display surface, such as a wearable device. - * <p> - * Similar to the requirements for becoming the default dialer/phone app, your app must declare a - * manifest entry for its {@link InCallService} implementation. Your manifest entry should - * ensure the following conditions are met: - * <ul> - * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li> - * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} - * metadata.</li> - * <li>Your app must request the permission - * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> - * </ul> - * <p> - * Your app should request to fill the role {@code android.app.role.CALL_COMPANION} in order to - * become a call companion app (see <a href="#requestRole">above</a> for how to request your app - * fills this role). */ public abstract class InCallService extends Service { diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java index 71a28b575394..eb568e04ebf3 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -17,6 +17,7 @@ package android.telecom; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Build; @@ -174,4 +175,21 @@ public final class PhoneAccountHandle implements Parcelable { in.readString(), UserHandle.CREATOR.createFromParcel(in)); } + + /** + * Determines if two {@link PhoneAccountHandle}s are from the same package. + * + * @param a Phone account handle to check for same {@link ConnectionService} package. + * @param b Other phone account handle to check for same {@link ConnectionService} package. + * @return {@code true} if the two {@link PhoneAccountHandle}s passed in belong to the same + * {@link ConnectionService} / package, {@code false} otherwise. Note: {@code null} phone + * account handles are considered equivalent to other {@code null} phone account handles. + * @hide + */ + public static boolean areFromSamePackage(@Nullable PhoneAccountHandle a, + @Nullable PhoneAccountHandle b) { + String aPackageName = a != null ? a.getComponentName().getPackageName() : null; + String bPackageName = b != null ? b.getComponentName().getPackageName() : null; + return Objects.equals(aPackageName, bPackageName); + } } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 391d788cfe72..db6319871540 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -16,7 +16,6 @@ package android.telecom; import android.Manifest; import android.annotation.IntDef; -import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; @@ -497,6 +496,9 @@ public class TelecomManager { * Dialer implementations (see {@link #getDefaultDialerPackage()}) which would also like to * override the system provided ringing should set this meta-data to {@code true} in the * manifest registration of their {@link InCallService}. + * <p> + * When {@code true}, it is the {@link InCallService}'s responsibility to play a ringtone for + * all incoming calls. */ public static final String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING"; @@ -1495,8 +1497,21 @@ public class TelecomManager { /** * Silences the ringer if a ringing call exists. - * - * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * <p> + * This method can only be relied upon to stop the ringtone for a call if the ringtone has + * already started playing. It is intended to handle use-cases such as silencing a ringing call + * when the user presses the volume button during ringing. + * <p> + * If this method is called prior to when the ringtone begins playing, the ringtone will not be + * silenced. As such it is not intended as a means to avoid playing of a ringtone. + * <p> + * A dialer app which wants to have more control over ringtone playing should declare + * {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} in the manifest entry for their + * {@link InCallService} implementation to indicate that the app wants to be responsible for + * playing the ringtone for all incoming calls. + * <p> + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or that the + * app fills the dialer role (see {@link #getDefaultDialerPackage()}). */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger() { diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 2d8a8cbae59f..037e47520c94 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -3394,6 +3394,7 @@ public final class Telephony { * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM, * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id. */ + @NonNull public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers"); /** @@ -3406,6 +3407,7 @@ public final class Telephony { * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM, * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id. */ + @NonNull public static final Uri SIM_APN_URI = Uri.parse( "content://telephony/carriers/sim_apn_list"); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 9f6528bc4709..d2f88bbda654 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2804,7 +2804,7 @@ public class CarrierConfigManager { * @hide */ public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = - "key_subscription_group_uuid_string"; + "subscription_group_uuid_string"; /** * A boolean property indicating whether this subscription should be managed as an opportunistic @@ -2819,7 +2819,7 @@ public class CarrierConfigManager { * @hide */ public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = - "key_is_opportunistic_subscription_bool"; + "is_opportunistic_subscription_bool"; /** * A list of 4 GSM RSSI thresholds above which a signal level is considered POOR, diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java index 78623e74277a..950ae6cf5ed8 100644 --- a/telephony/java/android/telephony/CarrierRestrictionRules.java +++ b/telephony/java/android/telephony/CarrierRestrictionRules.java @@ -336,7 +336,6 @@ public final class CarrierRestrictionRules implements Parcelable { public static final class Builder { private final CarrierRestrictionRules mRules; - /** {@hide} */ public Builder() { mRules = new CarrierRestrictionRules(); } diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index cf15b92ae640..c57f9e63f9db 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -39,6 +39,7 @@ import android.util.DisplayMetrics; import android.util.Log; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -123,6 +124,16 @@ public class SubscriptionInfo implements Parcelable { private String mMnc; /** + * EHPLMNs associated with the subscription + */ + private String[] mEhplmns; + + /** + * HPLMNs associated with the subscription + */ + private String[] mHplmns; + + /** * ISO Country code for the subscription's provider */ private String mCountryIso; @@ -316,6 +327,14 @@ public class SubscriptionInfo implements Parcelable { } /** + * @hide + */ + public void setAssociatedPlmns(String[] ehplmns, String[] hplmns) { + mEhplmns = ehplmns; + mHplmns = hplmns; + } + + /** * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a * user interface. * @@ -467,6 +486,20 @@ public class SubscriptionInfo implements Parcelable { } /** + * @hide + */ + public List<String> getEhplmns() { + return mEhplmns == null ? Collections.emptyList() : Arrays.asList(mEhplmns); + } + + /** + * @hide + */ + public List<String> getHplmns() { + return mHplmns == null ? Collections.emptyList() : Arrays.asList(mHplmns); + } + + /** * @return the profile class of this subscription. * @hide */ @@ -600,7 +633,7 @@ public class SubscriptionInfo implements Parcelable { String mcc = source.readString(); String mnc = source.readString(); String countryIso = source.readString(); - Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source); + Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader()); boolean isEmbedded = source.readBoolean(); UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR); String cardString = source.readString(); @@ -611,11 +644,15 @@ public class SubscriptionInfo implements Parcelable { int carrierid = source.readInt(); int profileClass = source.readInt(); int subType = source.readInt(); - - return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName, - nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso, - isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID, - isGroupDisabled, carrierid, profileClass, subType); + String[] ehplmns = source.readStringArray(); + String[] hplmns = source.readStringArray(); + + SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, + carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, + countryIso, isEmbedded, accessRules, cardString, cardId, isOpportunistic, + groupUUID, isGroupDisabled, carrierid, profileClass, subType); + info.setAssociatedPlmns(ehplmns, hplmns); + return info; } @Override @@ -638,7 +675,7 @@ public class SubscriptionInfo implements Parcelable { dest.writeString(mMcc); dest.writeString(mMnc); dest.writeString(mCountryIso); - mIconBitmap.writeToParcel(dest, flags); + dest.writeParcelable(mIconBitmap, flags); dest.writeBoolean(mIsEmbedded); dest.writeTypedArray(mAccessRules, flags); dest.writeString(mCardString); @@ -649,6 +686,8 @@ public class SubscriptionInfo implements Parcelable { dest.writeInt(mCarrierId); dest.writeInt(mProfileClass); dest.writeInt(mSubscriptionType); + dest.writeStringArray(mEhplmns); + dest.writeStringArray(mHplmns); } @Override @@ -686,6 +725,8 @@ public class SubscriptionInfo implements Parcelable { + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID + " mIsGroupDisabled=" + mIsGroupDisabled + " profileClass=" + mProfileClass + + " ehplmns = " + Arrays.toString(mEhplmns) + + " hplmns = " + Arrays.toString(mHplmns) + " subscriptionType=" + mSubscriptionType + "}"; } @@ -729,6 +770,8 @@ public class SubscriptionInfo implements Parcelable { && TextUtils.equals(mDisplayName, toCompare.mDisplayName) && TextUtils.equals(mCarrierName, toCompare.mCarrierName) && Arrays.equals(mAccessRules, toCompare.mAccessRules) - && mProfileClass == toCompare.mProfileClass; + && mProfileClass == toCompare.mProfileClass + && Arrays.equals(mEhplmns, toCompare.mEhplmns) + && Arrays.equals(mHplmns, toCompare.mHplmns); } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 0c6341111029..0808adf26aef 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -458,6 +458,18 @@ public class SubscriptionManager { public static final String CARRIER_ID = "carrier_id"; /** + * @hide A comma-separated list of EHPLMNs associated with the subscription + * <P>Type: TEXT (String)</P> + */ + public static final String EHPLMNS = "ehplmns"; + + /** + * @hide A comma-separated list of HPLMNs associated with the subscription + * <P>Type: TEXT (String)</P> + */ + public static final String HPLMNS = "hplmns"; + + /** * TelephonyProvider column name for the MCC associated with a SIM, stored as a string. * <P>Type: TEXT (String)</P> * @hide diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0d3bc1db831f..2bd4f8f336fd 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10376,10 +10376,10 @@ public class TelephonyManager { * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). * - * @return Map including the key as the active subscription ID (Note: if there is no active + * @return Map including the keys as the active subscription IDs (Note: if there is no active * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available; or throw - * a SecurityException if the caller does not have the permission. + * as the list of {@link EmergencyNumber}; empty Map if this information is not available; + * or throw a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull @@ -10429,10 +10429,10 @@ public class TelephonyManager { * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MIEC} </li> * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li> * </ol> - * @return Map including the key as the active subscription ID (Note: if there is no active + * @return Map including the keys as the active subscription IDs (Note: if there is no active * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available; or throw - * a SecurityException if the caller does not have the permission. + * as the list of {@link EmergencyNumber}; empty Map if this information is not available; + * or throw a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull diff --git a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java index e8fcac19f675..de4f17466a47 100644 --- a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java @@ -19,7 +19,6 @@ package android.telephony.ims.compat.feature; import android.annotation.IntDef; import android.annotation.UnsupportedAppUsage; import android.content.Context; -import android.content.Intent; import android.os.IInterface; import android.os.RemoteException; import android.telephony.SubscriptionManager; @@ -42,32 +41,6 @@ public abstract class ImsFeature { private static final String LOG_TAG = "ImsFeature"; - /** - * Action to broadcast when ImsService is up. - * Internal use only. - * Only defined here separately compatibility purposes with the old ImsService. - * @hide - */ - public static final String ACTION_IMS_SERVICE_UP = - "com.android.ims.IMS_SERVICE_UP"; - - /** - * Action to broadcast when ImsService is down. - * Internal use only. - * Only defined here separately for compatibility purposes with the old ImsService. - * @hide - */ - public static final String ACTION_IMS_SERVICE_DOWN = - "com.android.ims.IMS_SERVICE_DOWN"; - - /** - * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. - * A long value; the phone ID corresponding to the IMS service coming up or down. - * Only defined here separately for compatibility purposes with the old ImsService. - * @hide - */ - public static final String EXTRA_PHONE_ID = "android:phone_id"; - // Invalid feature value public static final int INVALID = -1; // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously @@ -162,30 +135,6 @@ public abstract class ImsFeature { } } } - sendImsServiceIntent(state); - } - - /** - * Provide backwards compatibility using deprecated service UP/DOWN intents. - */ - private void sendImsServiceIntent(@ImsState int state) { - if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - return; - } - Intent intent; - switch (state) { - case ImsFeature.STATE_NOT_AVAILABLE: - case ImsFeature.STATE_INITIALIZING: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - break; - case ImsFeature.STATE_READY: - intent = new Intent(ACTION_IMS_SERVICE_UP); - break; - default: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - } - intent.putExtra(EXTRA_PHONE_ID, mSlotId); - mContext.sendBroadcast(intent); } /** diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 5e3f3983b0a1..74af6bf6fe6e 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -20,7 +20,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; -import android.content.Intent; import android.os.IInterface; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -395,30 +394,6 @@ public abstract class ImsFeature { } } } - sendImsServiceIntent(state); - } - - /** - * Provide backwards compatibility using deprecated service UP/DOWN intents. - */ - private void sendImsServiceIntent(@ImsState int state) { - if (mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - return; - } - Intent intent; - switch (state) { - case ImsFeature.STATE_UNAVAILABLE: - case ImsFeature.STATE_INITIALIZING: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - break; - case ImsFeature.STATE_READY: - intent = new Intent(ACTION_IMS_SERVICE_UP); - break; - default: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - } - intent.putExtra(EXTRA_PHONE_ID, mSlotId); - mContext.sendBroadcast(intent); } /** diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java index e0d74e0908ee..c9e3404e0f1a 100644 --- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java +++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java @@ -34,6 +34,8 @@ import com.android.test.filters.SelectTest; public final class FrameworksTestsFilter extends SelectTest { private static final String[] SELECTED_TESTS = { + // Test specifications for FrameworksMockingCoreTests. + "android.app.activity.ActivityThreadClientTest", // Test specifications for FrameworksCoreTests. "android.app.servertransaction.", // all tests under the package. "android.view.DisplayCutoutTest", |