diff options
621 files changed, 12089 insertions, 12337 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 01edc71191f8..f602c9ad113d 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 @@ -571,6 +572,8 @@ package android { field public static final int endX = 16844050; // 0x1010512 field public static final int endY = 16844051; // 0x1010513 field @Deprecated public static final int endYear = 16843133; // 0x101017d + field public static final int ensuringNavigationBarContrastWhenTransparent = 16844203; // 0x10105ab + field public static final int ensuringStatusBarContrastWhenTransparent = 16844202; // 0x10105aa field public static final int enterFadeDuration = 16843532; // 0x101030c field public static final int entries = 16842930; // 0x10100b2 field public static final int entryValues = 16843256; // 0x10101f8 @@ -732,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 @@ -747,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 @@ -6232,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 { @@ -8998,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(); } @@ -10083,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); @@ -10166,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); @@ -10426,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 @@ -23039,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(); @@ -23244,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(); @@ -23416,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(); } @@ -23774,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); } @@ -24661,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(); @@ -24670,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); @@ -25142,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(); @@ -25553,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); @@ -26078,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(); @@ -26097,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"; @@ -26399,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; @@ -28754,10 +28513,13 @@ package android.net { public final class DnsResolver { method @NonNull public static android.net.DnsResolver getInstance(); - method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>); - method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>); - method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.InetAddressAnswerCallback); + method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>); + method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>); + method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>); + method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>); field public static final int CLASS_IN = 1; // 0x1 + field public static final int ERROR_PARSE = 0; // 0x0 + field public static final int ERROR_SYSTEM = 1; // 0x1 field public static final int FLAG_EMPTY = 0; // 0x0 field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4 field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2 @@ -28766,23 +28528,13 @@ package android.net { field public static final int TYPE_AAAA = 28; // 0x1c } - public abstract static class DnsResolver.AnswerCallback<T> { - ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>); - method public abstract void onAnswer(@NonNull T); - method public abstract void onParseException(@NonNull android.net.ParseException); - method public abstract void onQueryException(@NonNull android.system.ErrnoException); + public static interface DnsResolver.Callback<T> { + method public void onAnswer(@NonNull T, int); + method public void onError(@NonNull android.net.DnsResolver.DnsException); } - public static interface DnsResolver.AnswerParser<T> { - method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException; - } - - public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> { - ctor public DnsResolver.InetAddressAnswerCallback(); - } - - public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> { - ctor public DnsResolver.RawAnswerCallback(); + public static class DnsResolver.DnsException extends java.lang.Exception { + field public final int code; } public class InetAddresses { @@ -29108,8 +28860,6 @@ package android.net { } public class ParseException extends java.lang.RuntimeException { - ctor public ParseException(@NonNull String); - ctor public ParseException(@NonNull String, @NonNull Throwable); field public String response; } @@ -38589,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"; @@ -38672,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"; } @@ -38707,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"; } @@ -38760,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"; @@ -38818,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"; @@ -38862,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"; @@ -39333,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"; @@ -39352,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"; @@ -42013,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(); @@ -48055,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 @@ -48575,7 +48324,6 @@ package android.util { method public static boolean logEvent(int); method public static boolean logStart(int); method public static boolean logStop(int); - method public static void write(int, @NonNull java.lang.Object...); } public class StringBuilderPrinter implements android.util.Printer { @@ -50439,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(); @@ -50580,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(); @@ -50655,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); @@ -50781,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); @@ -50960,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 @@ -51770,6 +51509,7 @@ package android.view { method public android.transition.Transition getSharedElementReturnTransition(); method public boolean getSharedElementsUseOverlay(); method @ColorInt public abstract int getStatusBarColor(); + method @NonNull public java.util.List<android.graphics.Rect> getSystemGestureExclusionRects(); method public long getTransitionBackgroundFadeDuration(); method public android.transition.TransitionManager getTransitionManager(); method public abstract int getVolumeControlStream(); @@ -51781,6 +51521,8 @@ package android.view { method public void injectInputEvent(android.view.InputEvent); method public abstract void invalidatePanelMenu(int); method public final boolean isActive(); + method public boolean isEnsuringNavigationBarContrastWhenTransparent(); + method public boolean isEnsuringStatusBarContrastWhenTransparent(); method public abstract boolean isFloating(); method public abstract boolean isShortcutKey(int, android.view.KeyEvent); method public boolean isWideColorGamut(); @@ -51815,6 +51557,8 @@ package android.view { method protected void setDefaultWindowFormat(int); method public void setDimAmount(float); method public void setElevation(float); + method public void setEnsuringNavigationBarContrastWhenTransparent(boolean); + method public void setEnsuringStatusBarContrastWhenTransparent(boolean); method public void setEnterTransition(android.transition.Transition); method public void setExitTransition(android.transition.Transition); method public abstract void setFeatureDrawable(int, android.graphics.drawable.Drawable); @@ -51844,6 +51588,7 @@ package android.view { method public void setSoftInputMode(int); method public abstract void setStatusBarColor(@ColorInt int); method public void setSustainedPerformanceMode(boolean); + method public void setSystemGestureExclusionRects(@NonNull java.util.List<android.graphics.Rect>); method public abstract void setTitle(CharSequence); method @Deprecated public abstract void setTitleColor(@ColorInt int); method public void setTransitionBackgroundFadeDuration(long); @@ -53068,7 +52813,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); } @@ -53079,6 +52824,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); @@ -53093,24 +52839,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(); } @@ -53660,6 +53406,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(); @@ -53672,6 +53419,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); @@ -53868,29 +53616,23 @@ package android.view.textclassifier { method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig.Builder setIncludedTypes(@Nullable java.util.Collection<java.lang.String>); } - public final class TextClassifierEvent implements android.os.Parcelable { + public abstract class TextClassifierEvent implements android.os.Parcelable { method public int describeContents(); method @NonNull public int[] getActionIndices(); method @NonNull public String[] getEntityTypes(); method public int getEventCategory(); method @Nullable public android.view.textclassifier.TextClassificationContext getEventContext(); method public int getEventIndex(); - method public long getEventTime(); method public int getEventType(); method @NonNull public android.os.Bundle getExtras(); - method @Nullable public String getLanguage(); - method public int getRelativeSuggestedWordEndIndex(); - method public int getRelativeSuggestedWordStartIndex(); - method public int getRelativeWordEndIndex(); - method public int getRelativeWordStartIndex(); + method @Nullable public String getModelName(); method @Nullable public String getResultId(); - method public float getScore(); + method @NonNull public float[] getScores(); method public void writeToParcel(android.os.Parcel, int); field public static final int CATEGORY_CONVERSATION_ACTIONS = 3; // 0x3 field public static final int CATEGORY_LANGUAGE_DETECTION = 4; // 0x4 field public static final int CATEGORY_LINKIFY = 2; // 0x2 field public static final int CATEGORY_SELECTION = 1; // 0x1 - field public static final int CATEGORY_UNDEFINED = 0; // 0x0 field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent> CREATOR; field public static final int TYPE_ACTIONS_GENERATED = 20; // 0x14 field public static final int TYPE_ACTIONS_SHOWN = 6; // 0x6 @@ -53912,25 +53654,63 @@ package android.view.textclassifier { field public static final int TYPE_SMART_ACTION = 13; // 0xd field public static final int TYPE_SMART_SELECTION_MULTI = 4; // 0x4 field public static final int TYPE_SMART_SELECTION_SINGLE = 3; // 0x3 - field public static final int TYPE_UNDEFINED = 0; // 0x0 - } - - public static final class TextClassifierEvent.Builder { - ctor public TextClassifierEvent.Builder(int, int); - method @NonNull public android.view.textclassifier.TextClassifierEvent build(); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setActionIndices(@NonNull int...); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEntityTypes(@NonNull java.lang.String...); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventContext(@Nullable android.view.textclassifier.TextClassificationContext); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventTime(long); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setExtras(@NonNull android.os.Bundle); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setLanguage(@Nullable String); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordEndIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordStartIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordEndIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordStartIndex(int); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setResultId(@Nullable String); - method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setScore(float); + } + + public abstract static class TextClassifierEvent.Builder<T extends android.view.textclassifier.TextClassifierEvent.Builder<T>> { + method @NonNull public T setActionIndices(@NonNull int...); + method @NonNull public T setEntityTypes(@NonNull java.lang.String...); + method @NonNull public T setEventContext(@Nullable android.view.textclassifier.TextClassificationContext); + method @NonNull public T setEventIndex(int); + method @NonNull public T setExtras(@NonNull android.os.Bundle); + method @NonNull public T setModelName(@Nullable String); + method @NonNull public T setResultId(@Nullable String); + method @NonNull public T setScores(@NonNull float...); + } + + public static final class TextClassifierEvent.ConversationActionsEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent> CREATOR; + } + + public static final class TextClassifierEvent.ConversationActionsEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent.Builder> { + ctor public TextClassifierEvent.ConversationActionsEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent build(); + } + + public static final class TextClassifierEvent.LanguageDetectionEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + method @Nullable public android.icu.util.ULocale getLocale(); + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent> CREATOR; + } + + public static final class TextClassifierEvent.LanguageDetectionEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent.Builder> { + ctor public TextClassifierEvent.LanguageDetectionEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent build(); + method @NonNull public android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent.Builder setLocale(@Nullable android.icu.util.ULocale); + } + + public static final class TextClassifierEvent.TextLinkifyEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent> CREATOR; + } + + public static final class TextClassifierEvent.TextLinkifyEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent.Builder> { + ctor public TextClassifierEvent.TextLinkifyEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent build(); + } + + public static final class TextClassifierEvent.TextSelectionEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable { + method public int getRelativeSuggestedWordEndIndex(); + method public int getRelativeSuggestedWordStartIndex(); + method public int getRelativeWordEndIndex(); + method public int getRelativeWordStartIndex(); + field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.TextSelectionEvent> CREATOR; + } + + public static final class TextClassifierEvent.TextSelectionEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder> { + ctor public TextClassifierEvent.TextSelectionEvent.Builder(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent build(); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeSuggestedWordEndIndex(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeSuggestedWordStartIndex(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeWordEndIndex(int); + method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeWordStartIndex(int); } public final class TextLanguage implements android.os.Parcelable { @@ -54017,7 +53797,7 @@ package android.view.textclassifier { method public int getEnd(); method @NonNull public String getEntity(int); method public int getEntityCount(); - method public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method public int getStart(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks.TextLink> CREATOR; 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 c0da879241ab..b60e850249ef 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,14 @@ package android.app.prediction { } public static final class AppTarget.Builder { - ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId); + ctor @Deprecated 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); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { @@ -1217,7 +1218,6 @@ package android.app.usage { method public int getUsageSource(); method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent); - method @Deprecated @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent); method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String); method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String, long); @@ -1362,6 +1362,7 @@ package android.content { method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@RequiresPermission @NonNull android.content.Intent, @NonNull android.os.UserHandle); field public static final String APP_PREDICTION_SERVICE = "app_prediction"; field public static final String BACKUP_SERVICE = "backup"; + field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions"; field public static final String CONTEXTHUB_SERVICE = "contexthub"; field public static final String EUICC_CARD_SERVICE = "euicc_card"; @@ -2003,15 +2004,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 @@ -3497,11 +3498,11 @@ package android.media { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); method public void clearAudioServerStateCallback(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioProductStrategies getAudioProductStrategies(); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioVolumeGroups getAudioVolumeGroups(); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies(); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups(); + method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); + method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); + method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); method public boolean isHdmiSystemAudioSupported(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); @@ -3673,31 +3674,13 @@ 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; } - public final class AudioProductStrategies implements java.lang.Iterable<android.media.audiopolicy.AudioProductStrategy> android.os.Parcelable { - ctor public AudioProductStrategies(); - method public int describeContents(); - method @NonNull public android.media.AudioAttributes getAudioAttributesForLegacyStreamType(int); - method @NonNull public android.media.AudioAttributes getAudioAttributesForProductStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); - method @Nullable public android.media.audiopolicy.AudioProductStrategy getById(int); - method public int getLegacyStreamTypeForAudioAttributes(@NonNull android.media.AudioAttributes); - method @Nullable public android.media.audiopolicy.AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull android.media.AudioAttributes); - method public int getVolumeGroupIdForAttributes(@NonNull android.media.AudioAttributes); - method public int getVolumeGroupIdForLegacyStreamType(int); - method @NonNull public java.util.Iterator<android.media.audiopolicy.AudioProductStrategy> iterator(); - method public int size(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategies> CREATOR; - } - public final class AudioProductStrategy implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAudioAttributes(); method public int getId(); - method @NonNull public String name(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategy> CREATOR; } @@ -3710,16 +3693,6 @@ package android.media.audiopolicy { method @NonNull public String name(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioVolumeGroup> CREATOR; - } - - public final class AudioVolumeGroups implements java.lang.Iterable<android.media.audiopolicy.AudioVolumeGroup> android.os.Parcelable { - ctor public AudioVolumeGroups(); - method public int describeContents(); - method @Nullable public android.media.audiopolicy.AudioVolumeGroup getById(int); - method @NonNull public java.util.Iterator<android.media.audiopolicy.AudioVolumeGroup> iterator(); - method public int size(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioVolumeGroups> CREATOR; field public static final int DEFAULT_VOLUME_GROUP = -1; // 0xffffffff } @@ -4255,9 +4228,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 { @@ -5851,7 +5827,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); @@ -5859,7 +5834,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"; @@ -5892,10 +5866,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); @@ -6303,7 +6273,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); @@ -6424,9 +6393,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"; @@ -6526,7 +6495,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); @@ -6815,7 +6784,7 @@ package android.service.textclassifier { public abstract class TextClassifierService extends android.app.Service { ctor public TextClassifierService(); - method public static android.view.textclassifier.TextClassifier getDefaultTextClassifierImplementation(@NonNull android.content.Context); + method @NonNull public static android.view.textclassifier.TextClassifier getDefaultTextClassifierImplementation(@NonNull android.content.Context); method @Deprecated public final android.view.textclassifier.TextClassifier getLocalTextClassifier(); method @Nullable public final android.os.IBinder onBind(android.content.Intent); method @MainThread public abstract void onClassifyText(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassification.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>); @@ -7233,6 +7202,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>); @@ -9418,8 +9388,6 @@ package android.telephony.mbms.vendor { method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; method public void dispose(int) throws android.os.RemoteException; method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; - method public static String getDefaultTransactionName(int); - method public String getTransactionName(int); method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException; method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException; method public void onAppCallbackDied(int, int); @@ -9447,9 +9415,7 @@ package android.telephony.mbms.vendor { ctor public MbmsStreamingServiceBase(); method public android.os.IBinder asBinder(); method public void dispose(int) throws android.os.RemoteException; - method public static String getDefaultTransactionName(int); method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException; - method public String getTransactionName(int); method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException; method public void onAppCallbackDied(int, int); method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException; @@ -9479,22 +9445,6 @@ package android.telephony.mbms.vendor { package android.util { - public class DocumentsStatsLog { - method public static void logActivityLaunch(int, boolean, int, int); - method public static void logFileOperation(int, int); - method public static void logFileOperationCanceled(int); - method public static void logFileOperationCopyMoveMode(int, int); - method public static void logFileOperationFailure(int, int); - method public static void logFilePick(int, long, int, boolean, int, int, int); - method public static void logInvalidScopedAccessRequest(int); - method public static void logPickerLaunchedFrom(@Nullable String); - method public static void logRootVisited(int, int); - method public static void logSearchMode(int); - method public static void logSearchType(int); - method public static void logStartupMs(int); - method public static void logUserAction(int); - } - public class EventLog { method public static void readEventsOnWrapping(int[], long, java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException; } @@ -9507,22 +9457,6 @@ package android.util { method public static void writeRaw(@NonNull byte[], int); } - public class StatsLogAtoms { - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED = 170; // 0xaa - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED = 8; // 0x8 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED = 5; // 0x5 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED = 1; // 0x1 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED = 3; // 0x3 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION = 9; // 0x9 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED = 2; // 0x2 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED = 6; // 0x6 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE = 7; // 0x7 - field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED = 4; // 0x4 - } - - @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix="PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__", value={android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED}) public static @interface StatsLogAtoms.PermissionGrantRequestResultReported_Result { - } - } package android.view { 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 c3215a6867ae..f76b3830c461 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -498,12 +498,13 @@ 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); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); + method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { @@ -628,6 +629,7 @@ package android.content { method public int getUserId(); method public void setAutofillOptions(@Nullable android.content.AutofillOptions); method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions); + field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String ROLLBACK_SERVICE = "rollback"; field public static final String TEST_NETWORK_SERVICE = "test_network"; } @@ -1073,6 +1075,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(); } @@ -1084,6 +1099,16 @@ 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); + field public static final int SUCCESS = 0; // 0x0 + } + 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"; @@ -1107,29 +1132,6 @@ package android.media { field public static final String SAMPLE_RATE = "android.media.audiotrack.sampleRate"; } - public final class BufferingParams implements android.os.Parcelable { - method public int describeContents(); - method public int getInitialMarkMs(); - method public int getResumePlaybackMarkMs(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR; - } - - public static class BufferingParams.Builder { - ctor public BufferingParams.Builder(); - ctor public BufferingParams.Builder(android.media.BufferingParams); - method public android.media.BufferingParams build(); - method public android.media.BufferingParams.Builder setInitialMarkMs(int); - 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); @@ -1138,28 +1140,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); } @@ -1201,6 +1186,93 @@ 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 boolean removeUidDeviceAffinity(int); + method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; + method public void setRegistration(String); + method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>); + 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 { @@ -1365,6 +1437,7 @@ package android.net { } public class TestNetworkManager { + method public android.net.TestNetworkInterface createTapInterface(); method public android.net.TestNetworkInterface createTunInterface(@NonNull android.net.LinkAddress[]); method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder); method public void teardownTestNetwork(@NonNull android.net.Network); @@ -1375,9 +1448,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 } } @@ -1574,6 +1644,34 @@ package android.os { method @RequiresPermission("android.permission.POWER_SAVER") public boolean setChargingStateUpdateDelayMillis(int); } + public final class BugreportManager { + method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport(); + method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); + } + + public abstract static class BugreportManager.BugreportCallback { + ctor public BugreportManager.BugreportCallback(); + method public void onError(int); + method public void onFinished(); + method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float); + field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5 + field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1 + field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2 + field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4 + field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3 + } + + public final class BugreportParams { + ctor public BugreportParams(int); + method public int getMode(); + field public static final int BUGREPORT_MODE_FULL = 0; // 0x0 + field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1 + field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2 + field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4 + field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3 + field public static final int BUGREPORT_MODE_WIFI = 5; // 0x5 + } + public class Build { method public static boolean is64BitAbi(String); field public static final boolean IS_EMULATOR; @@ -2100,7 +2198,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); @@ -2108,7 +2205,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"; @@ -2122,10 +2218,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); @@ -2439,9 +2531,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"; @@ -2751,8 +2843,6 @@ package android.telephony.mbms.vendor { method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; method public void dispose(int) throws android.os.RemoteException; method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; - method public static String getDefaultTransactionName(int); - method public String getTransactionName(int); method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException; method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException; method public void onAppCallbackDied(int, int); @@ -2780,9 +2870,7 @@ package android.telephony.mbms.vendor { ctor public MbmsStreamingServiceBase(); method public android.os.IBinder asBinder(); method public void dispose(int) throws android.os.RemoteException; - method public static String getDefaultTransactionName(int); method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException; - method public String getTransactionName(int); method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException; method public void onAppCallbackDied(int, int); method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException; 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/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index df84b6a4dc34..a9f5208ef812 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -77,7 +77,6 @@ const int FIELD_ID_TIME_TO_LIVE_NANOS = 2; #define NS_PER_HOUR 3600 * NS_PER_SEC -#define STATS_DATA_DIR "/data/misc/stats-data" #define STATS_ACTIVE_METRIC_DIR "/data/misc/stats-active-metric" // Cool down period for writing data to disk to avoid overwriting files. @@ -106,6 +105,19 @@ StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap, StatsLogProcessor::~StatsLogProcessor() { } +static void flushProtoToBuffer(ProtoOutputStream& proto, vector<uint8_t>* outData) { + outData->clear(); + outData->resize(proto.size()); + size_t pos = 0; + sp<android::util::ProtoReader> reader = proto.data(); + while (reader->readBuffer() != NULL) { + size_t toRead = reader->currentToRead(); + std::memcpy(&((*outData)[pos]), reader->readBuffer(), toRead); + pos += toRead; + reader->move(toRead); + } +} + void StatsLogProcessor::onAnomalyAlarmFired( const int64_t& timestampNs, unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) { @@ -366,25 +378,29 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim proto->end(configKeyToken); // End of ConfigKey. + bool keepFile = false; + auto it = mMetricsManagers.find(key); + if (it != mMetricsManagers.end() && it->second->shouldPersistLocalHistory()) { + keepFile = true; + } + // Then, check stats-data directory to see there's any file containing // ConfigMetricsReport from previous shutdowns to concatenate to reports. - StorageManager::appendConfigMetricsReport(key, proto, erase_data); + StorageManager::appendConfigMetricsReport( + key, proto, erase_data && !keepFile /* should remove file after appending it */, + dumpReportReason == ADB_DUMP /*if caller is adb*/); - auto it = mMetricsManagers.find(key); if (it != mMetricsManagers.end()) { // This allows another broadcast to be sent within the rate-limit period if we get close to // filling the buffer again soon. mLastBroadcastTimes.erase(key); - // Start of ConfigMetricsReport (reports). - uint64_t reportsToken = - proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS); - onConfigMetricsReportLocked(key, dumpTimeStampNs, - include_current_partial_bucket, - erase_data, dumpReportReason, - dumpLatency, proto); - proto->end(reportsToken); - // End of ConfigMetricsReport (reports). + vector<uint8_t> buffer; + onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket, + erase_data, dumpReportReason, dumpLatency, + false /* is this data going to be saved on disk */, &buffer); + proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS, + reinterpret_cast<char*>(buffer.data()), buffer.size()); } else { ALOGW("Config source %s does not exist", key.ToString().c_str()); } @@ -404,16 +420,8 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim dumpReportReason, dumpLatency, &proto); if (outData != nullptr) { - outData->clear(); - outData->resize(proto.size()); - size_t pos = 0; - sp<android::util::ProtoReader> reader = proto.data(); - while (reader->readBuffer() != NULL) { - size_t toRead = reader->currentToRead(); - std::memcpy(&((*outData)[pos]), reader->readBuffer(), toRead); - pos += toRead; - reader->move(toRead); - } + flushProtoToBuffer(proto, outData); + VLOG("output data size %zu", outData->size()); } StatsdStats::getInstance().noteMetricsReportSent(key, proto.size()); @@ -422,13 +430,11 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim /* * onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData. */ -void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key, - const int64_t dumpTimeStampNs, - const bool include_current_partial_bucket, - const bool erase_data, - const DumpReportReason dumpReportReason, - const DumpLatency dumpLatency, - ProtoOutputStream* proto) { +void StatsLogProcessor::onConfigMetricsReportLocked( + const ConfigKey& key, const int64_t dumpTimeStampNs, + const bool include_current_partial_bucket, const bool erase_data, + const DumpReportReason dumpReportReason, const DumpLatency dumpLatency, + const bool dataSavedOnDisk, vector<uint8_t>* buffer) { // We already checked whether key exists in mMetricsManagers in // WriteDataToDisk. auto it = mMetricsManagers.find(key); @@ -440,35 +446,46 @@ void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key, std::set<string> str_set; + ProtoOutputStream tempProto; // First, fill in ConfigMetricsReport using current data on memory, which // starts from filling in StatsLogReport's. - it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, - erase_data, dumpLatency, &str_set, proto); + it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data, + dumpLatency, &str_set, &tempProto); // Fill in UidMap if there is at least one metric to report. // This skips the uid map if it's an empty config. if (it->second->getNumMetrics() > 0) { - uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP); + uint64_t uidMapToken = tempProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP); mUidMap->appendUidMap( dumpTimeStampNs, key, it->second->hashStringInReport() ? &str_set : nullptr, - it->second->versionStringsInReport(), it->second->installerInReport(), proto); - proto->end(uidMapToken); + it->second->versionStringsInReport(), it->second->installerInReport(), &tempProto); + tempProto.end(uidMapToken); } // Fill in the timestamps. - proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS, - (long long)lastReportTimeNs); - proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS, - (long long)dumpTimeStampNs); - proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS, - (long long)lastReportWallClockNs); - proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS, - (long long)getWallClockNs()); + tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS, + (long long)lastReportTimeNs); + tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS, + (long long)dumpTimeStampNs); + tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS, + (long long)lastReportWallClockNs); + tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS, + (long long)getWallClockNs()); // Dump report reason - proto->write(FIELD_TYPE_INT32 | FIELD_ID_DUMP_REPORT_REASON, dumpReportReason); + tempProto.write(FIELD_TYPE_INT32 | FIELD_ID_DUMP_REPORT_REASON, dumpReportReason); for (const auto& str : str_set) { - proto->write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | FIELD_ID_STRINGS, str); + tempProto.write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | FIELD_ID_STRINGS, str); + } + + flushProtoToBuffer(tempProto, buffer); + + // save buffer to disk if needed + if (erase_data && !dataSavedOnDisk && it->second->shouldPersistLocalHistory()) { + VLOG("save history to disk"); + string file_name = StorageManager::getDataHistoryFileName((long)getWallClockSec(), + key.GetUid(), key.GetId()); + StorageManager::writeFile(file_name.c_str(), buffer->data(), buffer->size()); } } @@ -584,18 +601,14 @@ void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key, !mMetricsManagers.find(key)->second->shouldWriteToDisk()) { return; } - ProtoOutputStream proto; + vector<uint8_t> buffer; onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/, - true /* erase_data */, dumpReportReason, dumpLatency, &proto); - string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, - (long)getWallClockSec(), key.GetUid(), (long long)key.GetId()); - android::base::unique_fd fd(open(file_name.c_str(), - O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR)); - if (fd == -1) { - ALOGE("Attempt to write %s but failed", file_name.c_str()); - return; - } - proto.flush(fd.get()); + true /* erase_data */, dumpReportReason, dumpLatency, true, + &buffer); + string file_name = + StorageManager::getDataFileName((long)getWallClockSec(), key.GetUid(), key.GetId()); + StorageManager::writeFile(file_name.c_str(), buffer.data(), buffer.size()); + // We were able to write the ConfigMetricsReport to disk, so we should trigger collection ASAP. mOnDiskDataConfigs.insert(key); } diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 305a4ce24b49..f4db0af29cef 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -164,12 +164,13 @@ private: const DumpReportReason dumpReportReason, const DumpLatency dumpLatency); - void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs, - const bool include_current_partial_bucket, - const bool erase_data, - const DumpReportReason dumpReportReason, - const DumpLatency dumpLatency, - util::ProtoOutputStream* proto); + void onConfigMetricsReportLocked( + const ConfigKey& key, const int64_t dumpTimeStampNs, + const bool include_current_partial_bucket, const bool erase_data, + const DumpReportReason dumpReportReason, const DumpLatency dumpLatency, + /*if dataSavedToDisk is true, it indicates the caller will write the data to disk + (e.g., before reboot). So no need to further persist local history.*/ + const bool dataSavedToDisk, vector<uint8_t>* proto); /* Check if we should send a broadcast if approaching memory limits and if we're over, we * actually delete the data. */ diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 90ba7ce0c812..d28108ceeb73 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -208,7 +208,7 @@ message Atom { 119 [(log_from_module) = "docsui"]; DocsUISearchTypeReported docs_ui_search_type_reported = 120 [(log_from_module) = "docsui"]; - DataStallEvent data_stall_event = 121; + DataStallEvent data_stall_event = 121 [(log_from_module) = "network_stack"]; RescuePartyResetReported rescue_party_reset_reported = 122; SignedConfigReported signed_config_reported = 123; GnssNiEventReported gnss_ni_event_reported = 124; @@ -257,7 +257,8 @@ message Atom { BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167; ScreenTimeoutExtensionReported screen_timeout_extension_reported = 168; ProcessStartTime process_start_time = 169; - PermissionGrantRequestResultReported permission_grant_request_result_reported = 170; + PermissionGrantRequestResultReported permission_grant_request_result_reported = + 170 [(log_from_module) = "permissioncontroller"]; BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171; DeviceIdentifierAccessDenied device_identifier_access_denied = 172; BubbleDeveloperErrorReported bubble_developer_error_reported = 173; @@ -267,9 +268,10 @@ message Atom { TouchGestureClassified touch_gesture_classified = 177; HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true]; StyleUIChanged style_ui_changed = 179; - PrivacyIndicatorsInteracted privacy_indicators_interacted = 180; + PrivacyIndicatorsInteracted privacy_indicators_interacted = + 180 [(log_from_module) = "permissioncontroller"]; AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181; - NetworkStackReported network_stack_reported = 182; + NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"]; AppMovedStorageReported app_moved_storage_reported = 183; BiometricEnrolled biometric_enrolled = 184; SystemServerWatchdogOccurred system_server_watchdog_occurred = 185; @@ -278,7 +280,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; @@ -338,6 +340,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. @@ -408,17 +412,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; } /** @@ -3122,6 +3134,8 @@ message BiometricAcquired { optional int32 acquire_info = 6; // Vendor-specific acquire info. Valid only if acquire_info == ACQUIRED_VENDOR. optional int32 acquire_info_vendor = 7; + // Dictates if this message should trigger additional debugging. + optional bool debug = 8; } /** @@ -3158,6 +3172,8 @@ message BiometricAuthenticated { // AUTHENTICATED. for setRequireConfirmation(true), this is from PENDING_CONFIRMATION to // CONFIRMED. optional int64 latency_millis = 7; + // Dictates if this message should trigger additional debugging. + optional bool debug = 8; } /** @@ -3183,6 +3199,8 @@ message BiometricErrorOccurred { // Vendor-specific error info. Valid only if acquire_info == ACQUIRED_VENDOR. These are defined // by the vendor and not specified by the HIDL interface. optional int32 error_info_vendor = 7; + // Dictates if this message should trigger additional debugging. + optional bool debug = 8; } /** @@ -3195,6 +3213,8 @@ message BiometricSystemHealthIssueDetected { optional android.hardware.biometrics.ModalityEnum modality = 1; // Type of issue detected. optional android.hardware.biometrics.IssueEnum issue = 2; + // Dictates if this message should trigger additional debugging. + optional bool debug = 3; } /** @@ -3947,8 +3967,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_. @@ -3960,6 +3979,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; } /** @@ -5575,6 +5597,7 @@ message BubbleUIChanged { SWIPE_LEFT = 13; SWIPE_RIGHT = 14; STACK_EXPANDED = 15; + FLYOUT = 16; } optional Action action = 6; @@ -5584,6 +5607,12 @@ message BubbleUIChanged { // Whether the bubble is unread. If it is unread, a dot is shown in the bubble stack icon. optional bool is_unread = 9; + + // Whether the bubble is an on-going one. + optional bool is_ongoing = 10; + + // Whether the bubble is produced by an app running in foreground. + optional bool is_foreground = 11; } /** @@ -5910,3 +5939,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/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 53f12acd3b84..4d21a29c1d82 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -145,6 +145,9 @@ public: // Maximum age (30 days) that files on disk can exist in seconds. static const int kMaxAgeSecond = 60 * 60 * 24 * 30; + // Maximum age (2 days) that local history files on disk can exist in seconds. + static const int kMaxLocalHistoryAgeSecond = 60 * 60 * 24 * 2; + // Maximum number of files (1000) that can be in stats directory on disk. static const int kMaxFileNumber = 1000; diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 095f9dde6129..6a55289bc8a2 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -65,7 +65,8 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, mTtlNs(config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1), mTtlEndNs(-1), mLastReportTimeNs(currentTimeNs), - mLastReportWallClockNs(getWallClockNs()) { + mLastReportWallClockNs(getWallClockNs()), + mShouldPersistHistory(config.persist_locally()) { // Init the ttl end timestamp. refreshTtl(timeBaseNs); diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index d317f8e00d82..00ae3b7028d9 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -78,6 +78,10 @@ public: return mNoReportMetricIds.size() != mAllMetricProducers.size(); } + bool shouldPersistLocalHistory() const { + return mShouldPersistHistory; + } + void dumpStates(FILE* out, bool verbose); inline bool isInTtl(const int64_t timestampNs) const { @@ -184,6 +188,8 @@ private: // Contains the annotations passed in with StatsdConfig. std::list<std::pair<const int64_t, const int32_t>> mAnnotations; + const bool mShouldPersistHistory; + // To guard access to mAllowedLogSources mutable std::mutex mAllowedLogSourcesMutex; diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 90a4e8b90051..c44ea8aa8ed0 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -633,10 +633,17 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn flushIfNeededLocked(eventTimeNs); } - // For pulled data, we already check condition when we decide to pull or - // in onDataPulled. So take all of them. - // For pushed data, just check condition. - if (!(mIsPulled || condition)) { + // We should not accumulate the data for pushed metrics when the condition is false. + bool shouldSkipForPushMetric = !mIsPulled && !condition; + // For pulled metrics, there are two cases: + // - to compute diffs, we need to process all the state changes + // - for non-diffs metrics, we should ignore the data if the condition wasn't true. If we have a + // state change from + // + True -> True: we should process the data, it might be a bucket boundary + // + True -> False: we als need to process the data. + bool shouldSkipForPulledMetric = mIsPulled && !mUseDiff + && mCondition != ConditionState::kTrue; + if (shouldSkipForPushMetric || shouldSkipForPulledMetric) { VLOG("ValueMetric skip event because condition is false"); return; } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 0f5633732db9..8c1999518ea6 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -259,6 +259,11 @@ private: FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff); FRIEND_TEST(ValueMetricProducerTest, TestPartialBucketCreated); FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries); + FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse); + FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue); + FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure); + FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges); + FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition); FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition); FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset); FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset); diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 257e65ee423d..2260b9b56d0b 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -439,6 +439,8 @@ message StatsdConfig { optional bool installer_in_metric_report = 19; + optional bool persist_locally = 20 [default = false]; + // Field number 1000 is reserved for later use. reserved 1000; } diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp index cf8b97494a06..0a9161d51cfe 100644 --- a/cmds/statsd/src/storage/StorageManager.cpp +++ b/cmds/statsd/src/storage/StorageManager.cpp @@ -56,9 +56,31 @@ std::mutex StorageManager::sTrainInfoMutex; using android::base::StringPrintf; using std::unique_ptr; -// Returns array of int64_t which contains timestamp in seconds, uid, and -// configID. -static void parseFileName(char* name, int64_t* result) { +struct FileName { + int64_t mTimestampSec; + int mUid; + int64_t mConfigId; + bool mIsHistory; + string getFullFileName(const char* path) { + return StringPrintf("%s/%lld_%d_%lld%s", path, (long long)mTimestampSec, (int)mUid, + (long long)mConfigId, (mIsHistory ? "_history" : "")); + }; +}; + +string StorageManager::getDataFileName(long wallClockSec, int uid, int64_t id) { + return StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, wallClockSec, uid, + (long long)id); +} + +string StorageManager::getDataHistoryFileName(long wallClockSec, int uid, int64_t id) { + return StringPrintf("%s/%ld_%d_%lld_history", STATS_DATA_DIR, wallClockSec, uid, + (long long)id); +} + +// Returns array of int64_t which contains timestamp in seconds, uid, +// configID and whether the file is a local history file. +static void parseFileName(char* name, FileName* output) { + int64_t result[3]; int index = 0; char* substr = strtok(name, "_"); while (substr != nullptr && index < 3) { @@ -72,11 +94,12 @@ static void parseFileName(char* name, int64_t* result) { if (index < 3) { result[0] = -1; } -} -static string getFilePath(const char* path, int64_t timestamp, int64_t uid, int64_t configID) { - return StringPrintf("%s/%lld_%d_%lld", path, (long long)timestamp, (int)uid, - (long long)configID); + output->mTimestampSec = result[0]; + output->mUid = result[1]; + output->mConfigId = result[2]; + // check if the file is a local history. + output->mIsHistory = (substr != nullptr && strcmp("history", substr) == 0); } void StorageManager::writeFile(const char* file, const void* buffer, int numBytes) { @@ -88,14 +111,13 @@ void StorageManager::writeFile(const char* file, const void* buffer, int numByte trimToFit(STATS_SERVICE_DIR); trimToFit(STATS_DATA_DIR); - int result = write(fd, buffer, numBytes); - if (result == numBytes) { + if (android::base::WriteFully(fd, buffer, numBytes)) { VLOG("Successfully wrote %s", file); } else { - VLOG("Failed to write %s", file); + ALOGE("Failed to write %s", file); } - result = fchown(fd, AID_STATSD, AID_STATSD); + int result = fchown(fd, AID_STATSD, AID_STATSD); if (result) { VLOG("Failed to chown %s to statsd", file); } @@ -349,13 +371,10 @@ void StorageManager::sendBroadcast(const char* path, if (name[0] == '.') continue; VLOG("file %s", name); - int64_t result[3]; - parseFileName(name, result); - if (result[0] == -1) continue; - int64_t uid = result[1]; - int64_t configID = result[2]; - - sendBroadcast(ConfigKey((int)uid, configID)); + FileName output; + parseFileName(name, &output); + if (output.mTimestampSec == -1 || output.mIsHistory) continue; + sendBroadcast(ConfigKey((int)output.mUid, output.mConfigId)); } } @@ -378,55 +397,58 @@ bool StorageManager::hasConfigMetricsReport(const ConfigKey& key) { if (suffixLen <= nameLen && strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) { // Check again that the file name is parseable. - int64_t result[3]; - parseFileName(name, result); - if (result[0] == -1) continue; + FileName output; + parseFileName(name, &output); + if (output.mTimestampSec == -1 || output.mIsHistory) continue; return true; } } return false; } -void StorageManager::appendConfigMetricsReport(const ConfigKey& key, - ProtoOutputStream* proto, - bool erasa_data) { +void StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto, + bool erase_data, bool isAdb) { unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir); if (dir == NULL) { VLOG("Path %s does not exist", STATS_DATA_DIR); return; } - string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId()); - dirent* de; while ((de = readdir(dir.get()))) { char* name = de->d_name; + string fileName(name); if (name[0] == '.') continue; + FileName output; + parseFileName(name, &output); - size_t nameLen = strlen(name); - size_t suffixLen = suffix.length(); - if (suffixLen <= nameLen && - strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) { - int64_t result[3]; - parseFileName(name, result); - if (result[0] == -1) continue; - int64_t timestamp = result[0]; - int64_t uid = result[1]; - int64_t configID = result[2]; - - string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID); - int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC); - if (fd != -1) { - string content; - if (android::base::ReadFdToString(fd, &content)) { - proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS, - content.c_str(), content.size()); - } - close(fd); + if (output.mTimestampSec == -1 || (output.mIsHistory && !isAdb) || + output.mUid != key.GetUid() || output.mConfigId != key.GetId()) { + continue; + } + + auto fullPathName = StringPrintf("%s/%s", STATS_DATA_DIR, fileName.c_str()); + int fd = open(fullPathName.c_str(), O_RDONLY | O_CLOEXEC); + if (fd != -1) { + string content; + if (android::base::ReadFdToString(fd, &content)) { + proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS, + content.c_str(), content.size()); } + close(fd); + } else { + ALOGE("file cannot be opened"); + } - if (erasa_data) { - remove(file_name.c_str()); + if (erase_data) { + remove(fullPathName.c_str()); + } else if (output.mIsHistory && !isAdb) { + // This means a real data owner has called to get this data. But the config says it + // wants to keep a local history. So now this file must be renamed as a history file. + // So that next time, when owner calls getData() again, this data won't be uploaded + // again. rename returns 0 on success + if (rename(fullPathName.c_str(), (fullPathName + "_history").c_str())) { + ALOGE("Failed to rename file %s", fullPathName.c_str()); } } } @@ -458,23 +480,20 @@ void StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap while ((de = readdir(dir.get()))) { char* name = de->d_name; if (name[0] == '.') continue; - VLOG("file %s", name); - int64_t result[3]; - parseFileName(name, result); - if (result[0] == -1) continue; - int64_t timestamp = result[0]; - int64_t uid = result[1]; - int64_t configID = result[2]; - string file_name = getFilePath(STATS_SERVICE_DIR, timestamp, uid, configID); + FileName output; + parseFileName(name, &output); + if (output.mTimestampSec == -1) continue; + string file_name = output.getFullFileName(STATS_SERVICE_DIR); int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC); if (fd != -1) { string content; if (android::base::ReadFdToString(fd, &content)) { StatsdConfig config; if (config.ParseFromString(content)) { - configsMap[ConfigKey(uid, configID)] = config; - VLOG("map key uid=%lld|configID=%lld", (long long)uid, (long long)configID); + configsMap[ConfigKey(output.mUid, output.mConfigId)] = config; + VLOG("map key uid=%lld|configID=%lld", (long long)output.mUid, + (long long)output.mConfigId); } } close(fd); @@ -533,6 +552,30 @@ bool StorageManager::hasIdenticalConfig(const ConfigKey& key, return false; } +void StorageManager::sortFiles(vector<FileInfo>* fileNames) { + // Reverse sort to effectively remove from the back (oldest entries). + // This will sort files in reverse-chronological order. Local history files have lower + // priority than regular data files. + sort(fileNames->begin(), fileNames->end(), [](FileInfo& lhs, FileInfo& rhs) { + // first consider if the file is a local history + if (lhs.mIsHistory && !rhs.mIsHistory) { + return false; + } else if (rhs.mIsHistory && !lhs.mIsHistory) { + return true; + } + + // then consider the age. + if (lhs.mFileAgeSec < rhs.mFileAgeSec) { + return true; + } else if (lhs.mFileAgeSec > rhs.mFileAgeSec) { + return false; + } + + // then good luck.... use string::compare + return lhs.mFileName.compare(rhs.mFileName) > 0; + }); +} + void StorageManager::trimToFit(const char* path) { unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir); if (dir == NULL) { @@ -541,55 +584,46 @@ void StorageManager::trimToFit(const char* path) { } dirent* de; int totalFileSize = 0; - vector<string> fileNames; + vector<FileInfo> fileNames; + auto nowSec = getWallClockSec(); while ((de = readdir(dir.get()))) { char* name = de->d_name; if (name[0] == '.') continue; - int64_t result[3]; - parseFileName(name, result); - if (result[0] == -1) continue; - int64_t timestamp = result[0]; - int64_t uid = result[1]; - int64_t configID = result[2]; - string file_name = getFilePath(path, timestamp, uid, configID); + FileName output; + parseFileName(name, &output); + if (output.mTimestampSec == -1) continue; + string file_name = output.getFullFileName(path); // Check for timestamp and delete if it's too old. - long fileAge = getWallClockSec() - timestamp; - if (fileAge > StatsdStats::kMaxAgeSecond) { + long fileAge = nowSec - output.mTimestampSec; + if (fileAge > StatsdStats::kMaxAgeSecond || + (output.mIsHistory && fileAge > StatsdStats::kMaxLocalHistoryAgeSecond)) { deleteFile(file_name.c_str()); + continue; } - fileNames.push_back(file_name); ifstream file(file_name.c_str(), ifstream::in | ifstream::binary); + int fileSize = 0; if (file.is_open()) { file.seekg(0, ios::end); - int fileSize = file.tellg(); + fileSize = file.tellg(); file.close(); totalFileSize += fileSize; } + fileNames.emplace_back(file_name, output.mIsHistory, fileSize, fileAge); } if (fileNames.size() > StatsdStats::kMaxFileNumber || totalFileSize > StatsdStats::kMaxFileSize) { - // Reverse sort to effectively remove from the back (oldest entries). - // This will sort files in reverse-chronological order. - sort(fileNames.begin(), fileNames.end(), std::greater<std::string>()); + sortFiles(&fileNames); } // Start removing files from oldest to be under the limit. while (fileNames.size() > 0 && (fileNames.size() > StatsdStats::kMaxFileNumber || totalFileSize > StatsdStats::kMaxFileSize)) { - string file_name = fileNames.at(fileNames.size() - 1); - ifstream file(file_name.c_str(), ifstream::in | ifstream::binary); - if (file.is_open()) { - file.seekg(0, ios::end); - int fileSize = file.tellg(); - file.close(); - totalFileSize -= fileSize; - } - - deleteFile(file_name.c_str()); + totalFileSize -= fileNames.at(fileNames.size() - 1).mFileSizeBytes; + deleteFile(fileNames.at(fileNames.size() - 1).mFileName.c_str()); fileNames.pop_back(); } } @@ -614,15 +648,13 @@ void StorageManager::printDirStats(int outFd, const char* path) { if (name[0] == '.') { continue; } - int64_t result[3]; - parseFileName(name, result); - if (result[0] == -1) continue; - int64_t timestamp = result[0]; - int64_t uid = result[1]; - int64_t configID = result[2]; - dprintf(outFd, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld", fileCount + 1, - (long long)timestamp, (int)uid, (long long)configID); - string file_name = getFilePath(path, timestamp, uid, configID); + FileName output; + parseFileName(name, &output); + if (output.mTimestampSec == -1) continue; + dprintf(outFd, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld, %s", fileCount + 1, + (long long)output.mTimestampSec, output.mUid, (long long)output.mConfigId, + (output.mIsHistory ? "local history" : "")); + string file_name = output.getFullFileName(path); ifstream file(file_name.c_str(), ifstream::in | ifstream::binary); if (file.is_open()) { file.seekg(0, ios::end); diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h index dfcea65b0872..69b41c2cb974 100644 --- a/cmds/statsd/src/storage/StorageManager.h +++ b/cmds/statsd/src/storage/StorageManager.h @@ -31,6 +31,19 @@ using android::util::ProtoOutputStream; class StorageManager : public virtual RefBase { public: + struct FileInfo { + FileInfo(std::string name, bool isHistory, int fileSize, long fileAge) + : mFileName(name), + mIsHistory(isHistory), + mFileSizeBytes(fileSize), + mFileAgeSec(fileAge) { + } + std::string mFileName; + bool mIsHistory; + int mFileSizeBytes; + long mFileAgeSec; + }; + /** * Writes a given byte array as a file to the specified file path. */ @@ -81,10 +94,19 @@ public: /** * Appends the ConfigMetricsReport found on disk to the specifid proto * and, if erase_data, deletes it from disk. + * + * [isAdb]: if the caller is adb dump. This includes local adb dump or dumpsys by + * bugreport or incidentd. When true, we will append any local history data too. + * + * When + * erase_data=true, isAdb=true: append history data to output, remove all data after read + * erase_data=false, isAdb=true: append history data to output, keep data after read + * erase_data=true, isAdb=false: do not append history data, and remove data after read + * erase_data=false, isAdb=false: do not append history data and *rename* all data files to + * history files. */ - static void appendConfigMetricsReport(const ConfigKey& key, - ProtoOutputStream* proto, - bool erase_data); + static void appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto, + bool erase_data, bool isAdb); /** * Call to load the saved configs from disk. @@ -115,6 +137,12 @@ public: */ static void printStats(int out); + static string getDataFileName(long wallClockSec, int uid, int64_t id); + + static string getDataHistoryFileName(long wallClockSec, int uid, int64_t id); + + static void sortFiles(vector<FileInfo>* fileNames); + private: /** * Prints disk usage statistics about a directory related to statsd. diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index c12a59003bab..43a3c7b0b2ea 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -2964,6 +2964,146 @@ TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) { EXPECT_EQ(10, report.value_metrics().data(0).bucket_info(0).condition_true_nanos()); } +TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); + metric.set_use_diff(false); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric); + + vector<shared_ptr<LogEvent>> allData; + allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 10)); + valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 30); + + // Bucket should have been completed. + assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs}); +} + +TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + metric.set_use_diff(false); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // condition becomes true + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(ValueMetricProducerTestHelper::createEvent( + bucketStartTimeNs + 30, 10)); + return true; + })) + // condition becomes false + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(ValueMetricProducerTestHelper::createEvent( + bucketStartTimeNs + 50, 20)); + return true; + })); + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric); + valueProducer->mCondition = ConditionState::kFalse; + + valueProducer->onConditionChanged(true, bucketStartTimeNs + 8); + valueProducer->onConditionChanged(false, bucketStartTimeNs + 50); + // has one slice + EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); + ValueMetricProducer::Interval curInterval = + valueProducer->mCurrentSlicedBucket.begin()->second[0]; + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(20, curInterval.value.long_value); + + + // Now the alarm is delivered. Condition is off though. + vector<shared_ptr<LogEvent>> allData; + allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110)); + valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8}); + curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0]; + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(false, curInterval.hasValue); +} + +TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + metric.set_use_diff(false); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // condition becomes true + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(ValueMetricProducerTestHelper::createEvent( + bucketStartTimeNs + 30, 10)); + return true; + })); + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric); + valueProducer->mCondition = ConditionState::kFalse; + + valueProducer->onConditionChanged(true, bucketStartTimeNs + 8); + + // Now the alarm is delivered. Condition is off though. + vector<shared_ptr<LogEvent>> allData; + allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 30)); + valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8}); + ValueMetricProducer::Interval curInterval = + valueProducer->mCurrentSlicedBucket.begin()->second[0]; + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(false, curInterval.hasValue); +} + +TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + metric.set_use_diff(false); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric); + valueProducer->mCondition = ConditionState::kFalse; + + // Now the alarm is delivered. Condition is off though. + vector<shared_ptr<LogEvent>> allData; + allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 30)); + valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + // Condition was always false. + assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}); +} + +TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + metric.set_use_diff(false); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // condition becomes true + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(ValueMetricProducerTestHelper::createEvent( + bucketStartTimeNs + 30, 10)); + return true; + })) + .WillOnce(Return(false)); + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric); + valueProducer->mCondition = ConditionState::kFalse; + + valueProducer->onConditionChanged(true, bucketStartTimeNs + 8); + valueProducer->onConditionChanged(false, bucketStartTimeNs + 50); + + // Now the alarm is delivered. Condition is off though. + vector<shared_ptr<LogEvent>> allData; + allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 30)); + valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + // No buckets, we had a failure. + assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}); +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp index 4564a5d058a3..cae2f3069855 100644 --- a/cmds/statsd/tests/storage/StorageManager_test.cpp +++ b/cmds/statsd/tests/storage/StorageManager_test.cpp @@ -110,6 +110,21 @@ TEST(StorageManagerTest, TrainInfoReadWriteTrainNameSizeOneTest) { EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds); } +TEST(StorageManagerTest, SortFileTest) { + vector<StorageManager::FileInfo> list; + // assume now sec is 500 + list.emplace_back("200_5000_123454", false, 20, 300); + list.emplace_back("300_2000_123454_history", true, 30, 200); + list.emplace_back("400_100009_123454_history", true, 40, 100); + list.emplace_back("100_2000_123454", false, 50, 400); + + StorageManager::sortFiles(&list); + EXPECT_EQ("200_5000_123454", list[0].mFileName); + EXPECT_EQ("100_2000_123454", list[1].mFileName); + EXPECT_EQ("400_100009_123454_history", list[2].mFileName); + EXPECT_EQ("300_2000_123454_history", list[3].mFileName); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 9079ace4b8a3..6e935e1e56c4 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -127,7 +127,6 @@ import android.view.autofill.AutofillPopupWindow; import android.view.autofill.IAutofillWindowPresenter; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureManager; -import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient; import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; @@ -724,7 +723,7 @@ public class Activity extends ContextThemeWrapper Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback, - AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient { + AutofillManager.AutofillClient { private static final String TAG = "Activity"; private static final boolean DEBUG_LIFECYCLE = false; @@ -1124,12 +1123,6 @@ public class Activity extends ContextThemeWrapper return this; } - /** @hide */ - @Override - public final ContentCaptureClient getContentCaptureClient() { - return this; - } - /** * Register an {@link Application.ActivityLifecycleCallbacks} instance that receives * lifecycle callbacks for only this Activity. @@ -4909,10 +4902,11 @@ public class Activity extends ContextThemeWrapper final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q; if (!targetPreQ) { mTaskDescription.setEnsureStatusBarContrastWhenTransparent(a.getBoolean( - R.styleable.ActivityTaskDescription_ensureStatusBarContrastWhenTransparent, + R.styleable.ActivityTaskDescription_ensuringStatusBarContrastWhenTransparent, false)); mTaskDescription.setEnsureNavigationBarContrastWhenTransparent(a.getBoolean( - R.styleable.ActivityTaskDescription_ensureNavigationBarContrastWhenTransparent, + R.styleable + .ActivityTaskDescription_ensuringNavigationBarContrastWhenTransparent, true)); } @@ -6508,12 +6502,6 @@ public class Activity extends ContextThemeWrapper return getComponentName(); } - /** @hide */ - @Override - public final ComponentName contentCaptureClientGetComponentName() { - return getComponentName(); - } - /** * Retrieve a {@link SharedPreferences} object for accessing preferences * that are private to this activity. This simply calls the underlying diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4f388a441aab..cf4ef205b303 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1838,17 +1838,17 @@ public class ActivityManager { private final float mScale; private final int mSystemUiVisibility; private final boolean mIsTranslucent; - - // TODO(b/116112787) TaskSnapshot must also book keep the color space from hardware bitmap - // when created. - private final ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); + // Must be one of the named color spaces, otherwise, always use SRGB color space. + private final ColorSpace mColorSpace; public TaskSnapshot(@NonNull ComponentName topActivityComponent, GraphicBuffer snapshot, - int orientation, Rect contentInsets, boolean reducedResolution, float scale, - boolean isRealSnapshot, int windowingMode, int systemUiVisibility, - boolean isTranslucent) { + @NonNull ColorSpace colorSpace, int orientation, Rect contentInsets, + boolean reducedResolution, float scale, boolean isRealSnapshot, int windowingMode, + int systemUiVisibility, boolean isTranslucent) { mTopActivityComponent = topActivityComponent; mSnapshot = snapshot; + mColorSpace = colorSpace.getId() < 0 + ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace; mOrientation = orientation; mContentInsets = new Rect(contentInsets); mReducedResolution = reducedResolution; @@ -1862,6 +1862,10 @@ public class ActivityManager { private TaskSnapshot(Parcel source) { mTopActivityComponent = ComponentName.readFromParcel(source); mSnapshot = source.readParcelable(null /* classLoader */); + int colorSpaceId = source.readInt(); + mColorSpace = colorSpaceId >= 0 + ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]) + : ColorSpace.get(ColorSpace.Named.SRGB); mOrientation = source.readInt(); mContentInsets = source.readParcelable(null /* classLoader */); mReducedResolution = source.readBoolean(); @@ -1968,6 +1972,7 @@ public class ActivityManager { public void writeToParcel(Parcel dest, int flags) { ComponentName.writeToParcel(mTopActivityComponent, dest); dest.writeParcelable(mSnapshot, 0); + dest.writeInt(mColorSpace.getId()); dest.writeInt(mOrientation); dest.writeParcelable(mContentInsets, 0); dest.writeBoolean(mReducedResolution); @@ -1985,6 +1990,7 @@ public class ActivityManager { return "TaskSnapshot{" + " mTopActivityComponent=" + mTopActivityComponent.flattenToShortString() + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")" + + " mColorSpace=" + mColorSpace.toString() + " mOrientation=" + mOrientation + " mContentInsets=" + mContentInsets.toShortString() + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b37d117238af..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; } } @@ -2121,7 +2105,11 @@ public final class ActivityThread extends ClientTransactionHandler { } LoadedApk packageInfo = ref != null ? ref.get() : null; - if (ai != null && packageInfo != null && isLoadedApkUpToDate(packageInfo, ai)) { + if (ai != null && packageInfo != null) { + if (!isLoadedApkResourceDirsUpToDate(packageInfo, ai)) { + packageInfo.updateApplicationInfo(ai, null); + } + if (packageInfo.isSecurityViolation() && (flags&Context.CONTEXT_IGNORE_SECURITY) == 0) { throw new SecurityException( @@ -2205,9 +2193,11 @@ public final class ActivityThread extends ClientTransactionHandler { LoadedApk packageInfo = ref != null ? ref.get() : null; - boolean isUpToDate = packageInfo != null && isLoadedApkUpToDate(packageInfo, aInfo); + if (packageInfo != null) { + if (!isLoadedApkResourceDirsUpToDate(packageInfo, aInfo)) { + packageInfo.updateApplicationInfo(aInfo, null); + } - if (isUpToDate) { return packageInfo; } @@ -2243,11 +2233,8 @@ public final class ActivityThread extends ClientTransactionHandler { } } - /** - * Compares overlay/resource directories for a LoadedApk to determine if it's up to date - * with the given ApplicationInfo. - */ - private boolean isLoadedApkUpToDate(LoadedApk loadedApk, ApplicationInfo appInfo) { + private static boolean isLoadedApkResourceDirsUpToDate(LoadedApk loadedApk, + ApplicationInfo appInfo) { Resources packageResources = loadedApk.mResources; String[] overlayDirs = ArrayUtils.defeatNullable(loadedApk.getOverlayDirs()); String[] resourceDirs = ArrayUtils.defeatNullable(appInfo.resourceDirs); @@ -2930,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, @@ -4500,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(); @@ -4561,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 */); } } @@ -4578,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()); } } @@ -5414,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 @@ -5460,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) { @@ -6495,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..227703d7c027 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; @@ -824,9 +823,11 @@ public class AppOpsManager { public static final int OP_LEGACY_STORAGE = 87; /** @hide Accessing accessibility features */ public static final int OP_ACCESS_ACCESSIBILITY = 88; + /** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */ + public static final int OP_READ_DEVICE_IDENTIFIERS = 89; /** @hide */ @UnsupportedAppUsage - public static final int _NUM_OP = 89; + public static final int _NUM_OP = 90; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1100,6 +1101,8 @@ public class AppOpsManager { /** @hide Interact with accessibility. */ @SystemApi public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; + /** @hide Read device identifiers */ + public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers"; // Warning: If an permission is added here it also has to be added to // com.android.packageinstaller.permission.utils.EventLogger @@ -1260,6 +1263,7 @@ public class AppOpsManager { OP_WRITE_MEDIA_IMAGES, // WRITE_MEDIA_IMAGES OP_LEGACY_STORAGE, // LEGACY_STORAGE OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY + OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS }; /** @@ -1355,6 +1359,7 @@ public class AppOpsManager { OPSTR_WRITE_MEDIA_IMAGES, OPSTR_LEGACY_STORAGE, OPSTR_ACCESS_ACCESSIBILITY, + OPSTR_READ_DEVICE_IDENTIFIERS, }; /** @@ -1451,6 +1456,7 @@ public class AppOpsManager { "WRITE_MEDIA_IMAGES", "LEGACY_STORAGE", "ACCESS_ACCESSIBILITY", + "READ_DEVICE_IDENTIFIERS", }; /** @@ -1548,6 +1554,7 @@ public class AppOpsManager { null, // no permission for OP_WRITE_MEDIA_IMAGES null, // no permission for OP_LEGACY_STORAGE null, // no permission for OP_ACCESS_ACCESSIBILITY + null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS }; /** @@ -1645,6 +1652,7 @@ public class AppOpsManager { null, // WRITE_MEDIA_IMAGES null, // LEGACY_STORAGE null, // ACCESS_ACCESSIBILITY + null, // READ_DEVICE_IDENTIFIERS }; /** @@ -1741,6 +1749,7 @@ public class AppOpsManager { false, // WRITE_MEDIA_IMAGES false, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY + false, // READ_DEVICE_IDENTIFIERS }; /** @@ -1836,6 +1845,7 @@ public class AppOpsManager { AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY + AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS }; /** @@ -1935,6 +1945,7 @@ public class AppOpsManager { false, // WRITE_MEDIA_IMAGES false, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY + false, // READ_DEVICE_IDENTIFIERS }; /** @@ -5209,7 +5220,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 +5248,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 +5355,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 +5371,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 +5710,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/LoadedApk.java b/core/java/android/app/LoadedApk.java index e16ce24cbb2c..310cce41fa41 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -781,16 +781,6 @@ public final class LoadedApk { isBundledApp = false; } - // Similar to vendor apks, we should add /product/lib for apks from product partition - // and not having /product/lib in the default search path - final boolean treatProductApkAsUnbundled = !defaultSearchPaths.contains("/product/lib"); - if (mApplicationInfo.getCodePath() != null - && mApplicationInfo.isProduct() && treatProductApkAsUnbundled - // TODO(b/128557860): Change target SDK version when version code R is available. - && getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) { - isBundledApp = false; - } - makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths); String libraryPermittedPath = mDataDir; 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/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 8749b108c168..98b658d3ad25 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -367,7 +367,7 @@ final class SystemServiceRegistry { throw new ServiceNotFoundException(Context.TEST_NETWORK_SERVICE); } ITestNetworkManager tnMgr = ITestNetworkManager.Stub.asInterface(tnBinder); - return new TestNetworkManager(context, tnMgr); + return new TestNetworkManager(tnMgr); } }); 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..61e4569c1228 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 */ + @Deprecated @SystemApi - @TestApi 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. */ @NonNull + @Deprecated public Builder setTarget(@NonNull String packageName, @NonNull UserHandle user) { if (mPackageName != null) { throw new IllegalArgumentException("Target is already set"); @@ -232,11 +257,10 @@ 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. */ @NonNull + @Deprecated public Builder setTarget(@NonNull ShortcutInfo info) { setTarget(info.getPackage(), info.getUserHandle()); mShortcutInfo = Preconditions.checkNotNull(info); @@ -244,7 +268,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 +277,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 +298,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/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java index 027e152ee95f..394a0d64b3e4 100644 --- a/core/java/android/app/role/RoleControllerManager.java +++ b/core/java/android/app/role/RoleControllerManager.java @@ -52,7 +52,10 @@ public class RoleControllerManager { private static final String LOG_TAG = RoleControllerManager.class.getSimpleName(); + private static volatile ComponentName sRemoteServiceComponentName; + private static final Object sRemoteServicesLock = new Object(); + /** * Global remote services (per user) used by all {@link RoleControllerManager managers}. */ @@ -62,18 +65,36 @@ public class RoleControllerManager { @NonNull private final RemoteService mRemoteService; - public RoleControllerManager(@NonNull Context context, @NonNull Handler handler) { + /** + * Initialize the remote service component name once so that we can avoid acquiring the + * PackageManagerService lock in constructor. + * + * @see #createWithInitializedRemoteServiceComponentName(Handler, Context) + */ + public static void initializeRemoteServiceComponentName(@NonNull Context context) { + sRemoteServiceComponentName = getRemoteServiceComponentName(context); + } + + /** + * Create a {@link RoleControllerManager} instance with the initialized remote service component + * name so that we can avoid acquiring the PackageManagerService lock in constructor. + * + * @see #initializeRemoteServiceComponentName(Context) + */ + @NonNull + public static RoleControllerManager createWithInitializedRemoteServiceComponentName( + @NonNull Handler handler, @NonNull Context context) { + return new RoleControllerManager(sRemoteServiceComponentName, handler, context); + } + + private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName, + @NonNull Handler handler, @NonNull Context context) { synchronized (sRemoteServicesLock) { int userId = context.getUserId(); RemoteService remoteService = sRemoteServices.get(userId); if (remoteService == null) { - Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE); - PackageManager packageManager = context.getPackageManager(); - intent.setPackage(packageManager.getPermissionControllerPackageName()); - ResolveInfo resolveInfo = packageManager.resolveService(intent, 0); - remoteService = new RemoteService(context.getApplicationContext(), - resolveInfo.getComponentInfo().getComponentName(), handler, userId); + remoteServiceComponentName, handler, userId); sRemoteServices.put(userId, remoteService); } mRemoteService = remoteService; @@ -81,7 +102,16 @@ public class RoleControllerManager { } public RoleControllerManager(@NonNull Context context) { - this(context, context.getMainThreadHandler()); + this(getRemoteServiceComponentName(context), context.getMainThreadHandler(), context); + } + + @NonNull + private static ComponentName getRemoteServiceComponentName(@NonNull Context context) { + Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE); + PackageManager packageManager = context.getPackageManager(); + intent.setPackage(packageManager.getPermissionControllerPackageName()); + ResolveInfo resolveInfo = packageManager.resolveService(intent, 0); + return resolveInfo.getComponentInfo().getComponentName(); } /** 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/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index eb1ea90e4382..f8dc20e9af09 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -678,29 +678,6 @@ public final class UsageStatsManager { } } - - /** - * @deprecated use {@link #registerUsageSessionObserver(int, String[], Duration, Duration, - * PendingIntent, PendingIntent)}. - * - * @hide - */ - @Deprecated - @SystemApi - @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) - // STOPSHIP b/128455269: remove this method - public void registerUsageSessionObserver(int sessionObserverId, - @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit, - long sessionThresholdTime, @NonNull TimeUnit sessionThresholdTimeUnit, - @NonNull PendingIntent limitReachedCallbackIntent, - @Nullable PendingIntent sessionEndCallbackIntent) { - final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit)); - final Duration sessionThresholdDuration = - Duration.ofMillis(sessionThresholdTimeUnit.toMillis(sessionThresholdTime)); - registerUsageSessionObserver(sessionObserverId, observedEntities, timeLimitDuration, - sessionThresholdDuration, limitReachedCallbackIntent, sessionEndCallbackIntent); - } - /** * Register a usage session observer that receives a callback on the provided {@code * limitReachedCallbackIntent} when the sum of usages of apps and tokens in the {@code 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/AutofillOptions.java b/core/java/android/content/AutofillOptions.java index f59bc9891c86..8fb9501b3319 100644 --- a/core/java/android/content/AutofillOptions.java +++ b/core/java/android/content/AutofillOptions.java @@ -24,7 +24,7 @@ import android.os.Parcelable; import android.util.ArraySet; import android.util.Log; import android.view.autofill.AutofillManager; -import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient; +import android.view.autofill.AutofillManager.AutofillClient; import java.io.PrintWriter; @@ -73,10 +73,10 @@ public final class AutofillOptions implements Parcelable { public boolean isAugmentedAutofillEnabled(@NonNull Context context) { if (!augmentedAutofillEnabled) return false; - final ContentCaptureClient contentCaptureClient = context.getContentCaptureClient(); - if (contentCaptureClient == null) return false; + final AutofillClient autofillClient = context.getAutofillClient(); + if (autofillClient == null) return false; - final ComponentName component = contentCaptureClient.contentCaptureClientGetComponentName(); + final ComponentName component = autofillClient.autofillClientGetComponentName(); return whitelistedActivitiesForAugmentedAutofill == null || whitelistedActivitiesForAugmentedAutofill.contains(component); } 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/Context.java b/core/java/android/content/Context.java index af738da20621..0ba457e65c67 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -70,7 +70,6 @@ import android.view.View; import android.view.ViewDebug; import android.view.WindowManager; import android.view.autofill.AutofillManager.AutofillClient; -import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient; import android.view.textclassifier.TextClassificationManager; import java.io.File; @@ -3820,10 +3819,7 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a {@link - * android.net.wifi.rtt.WifiRttManager} for ranging devices with wifi - * - * Note: this is a replacement for WIFI_RTT_SERVICE above. It will - * be renamed once final implementation in place. + * android.net.wifi.rtt.WifiRttManager} for ranging devices with wifi. * * @see #getSystemService(String) * @see android.net.wifi.rtt.WifiRttManager @@ -4567,8 +4563,7 @@ public abstract class Context { * @see android.os.BugreportManager * @hide */ - // TODO: Expose API when the implementation is more complete. - // @SystemApi + @SystemApi @TestApi public static final String BUGREPORT_SERVICE = "bugreport"; /** @@ -5418,14 +5413,6 @@ public abstract class Context { /** * @hide */ - @Nullable - public ContentCaptureClient getContentCaptureClient() { - return null; - } - - /** - * @hide - */ public final boolean isAutofillCompatibilityEnabled() { final AutofillOptions options = getAutofillOptions(); return options != null && options.compatModeEnabled; 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 a71f7d2c6455..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} */ @@ -1222,7 +1221,7 @@ public class PackageInstaller { try { mSession.addChildSessionId(sessionId); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } @@ -1236,7 +1235,7 @@ public class PackageInstaller { try { mSession.removeChildSessionId(sessionId); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } } diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 9e0ee5884199..d3575c03c9f6 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1252,6 +1252,7 @@ public abstract class CameraMetadata<TKey> { * fire the flash for flash power metering during precapture, and then fire the flash * for the final capture, if a flash is available on the device and the AE mode is set to * enable the flash.</p> + * <p>Devices that initially shipped with Android version {@link android.os.Build.VERSION_CODES#Q Q} or newer will not include any LEGACY-level devices.</p> * * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES 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/DnsResolver.java b/core/java/android/net/DnsResolver.java index 06c32c675a31..68826cbeb845 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -93,6 +93,23 @@ public final class DnsResolver { public static final int FLAG_NO_CACHE_STORE = 1 << 1; public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2; + @IntDef(prefix = { "ERROR_" }, value = { + ERROR_PARSE, + ERROR_SYSTEM + }) + @Retention(RetentionPolicy.SOURCE) + @interface DnsError {} + /** + * Indicates that there was an error parsing the response the query. + * The cause of this error is available via getCause() and is a ParseException. + */ + public static final int ERROR_PARSE = 0; + /** + * Indicates that there was an error sending the query. + * The cause of this error is available via getCause() and is an ErrnoException. + */ + public static final int ERROR_SYSTEM = 1; + private static final int NETID_UNSET = 0; private static final DnsResolver sInstance = new DnsResolver(); @@ -107,97 +124,57 @@ public final class DnsResolver { private DnsResolver() {} /** - * Answer parser for parsing raw answers + * Base interface for answer callbacks * - * @param <T> The type of the parsed answer + * @param <T> The type of the answer */ - public interface AnswerParser<T> { - /** - * Creates a <T> answer by parsing the given raw answer. - * - * @param rawAnswer the raw answer to be parsed - * @return a parsed <T> answer - * @throws ParseException if parsing failed - */ - @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException; - } - - /** - * Base class for answer callbacks - * - * @param <T> The type of the parsed answer - */ - public abstract static class AnswerCallback<T> { - /** @hide */ - public final AnswerParser<T> parser; - - public AnswerCallback(@NonNull AnswerParser<T> parser) { - this.parser = parser; - }; - + public interface Callback<T> { /** * Success response to - * {@link android.net.DnsResolver#query query()}. + * {@link android.net.DnsResolver#query query()} or + * {@link android.net.DnsResolver#rawQuery rawQuery()}. * * Invoked when the answer to a query was successfully parsed. * - * @param answer parsed answer to the query. + * @param answer <T> answer to the query. + * @param rcode The response code in the DNS response. * * {@see android.net.DnsResolver#query query()} */ - public abstract void onAnswer(@NonNull T answer); - + void onAnswer(@NonNull T answer, int rcode); /** * Error response to - * {@link android.net.DnsResolver#query query()}. + * {@link android.net.DnsResolver#query query()} or + * {@link android.net.DnsResolver#rawQuery rawQuery()}. * * Invoked when there is no valid answer to * {@link android.net.DnsResolver#query query()} + * {@link android.net.DnsResolver#rawQuery rawQuery()}. * - * @param exception a {@link ParseException} object with additional + * @param error a {@link DnsException} object with additional * detail regarding the failure */ - public abstract void onParseException(@NonNull ParseException exception); - - /** - * Error response to - * {@link android.net.DnsResolver#query query()}. - * - * Invoked if an error happens when - * issuing the DNS query or receiving the result. - * {@link android.net.DnsResolver#query query()} - * - * @param exception an {@link ErrnoException} object with additional detail - * regarding the failure - */ - public abstract void onQueryException(@NonNull ErrnoException exception); + void onError(@NonNull DnsException error); } /** - * Callback for receiving raw answers + * Class to represent DNS error */ - public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> { - public RawAnswerCallback() { - super(rawAnswer -> rawAnswer); - } - } - - /** - * Callback for receiving parsed {@link InetAddress} answers - * - * Note that if the answer does not contain any IP addresses, - * onAnswer will be called with an empty list. - */ - public abstract static class InetAddressAnswerCallback - extends AnswerCallback<List<InetAddress>> { - public InetAddressAnswerCallback() { - super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses()); + public static class DnsException extends Exception { + /** + * DNS error code as one of the ERROR_* constants + */ + @DnsError public final int code; + + DnsException(@DnsError int code, @Nullable Throwable cause) { + super(cause); + this.code = code; } } /** * Send a raw DNS query. - * The answer will be provided asynchronously through the provided {@link AnswerCallback}. + * The answer will be provided asynchronously through the provided {@link Callback}. * * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. @@ -206,13 +183,13 @@ public final class DnsResolver { * @param executor The {@link Executor} that the callback should be executed on. * @param cancellationSignal used by the caller to signal if the query should be * cancelled. May be {@code null}. - * @param callback an {@link AnswerCallback} which will be called to notify the caller + * @param callback a {@link Callback} which will be called to notify the caller * of the result of dns query. */ - public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, + public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, @NonNull @CallbackExecutor Executor executor, @Nullable CancellationSignal cancellationSignal, - @NonNull AnswerCallback<T> callback) { + @NonNull Callback<? super byte[]> callback) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } @@ -220,11 +197,9 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkSend((network != null - ? network.netId : NETID_UNSET), query, query.length, flags); + ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags); } catch (ErrnoException e) { - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } @@ -237,7 +212,7 @@ public final class DnsResolver { /** * Send a DNS query with the specified name, class and query type. - * The answer will be provided asynchronously through the provided {@link AnswerCallback}. + * The answer will be provided asynchronously through the provided {@link Callback}. * * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. @@ -248,14 +223,14 @@ public final class DnsResolver { * @param executor The {@link Executor} that the callback should be executed on. * @param cancellationSignal used by the caller to signal if the query should be * cancelled. May be {@code null}. - * @param callback an {@link AnswerCallback} which will be called to notify the caller + * @param callback a {@link Callback} which will be called to notify the caller * of the result of dns query. */ - public <T> void query(@Nullable Network network, @NonNull String domain, + public void rawQuery(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags, @NonNull @CallbackExecutor Executor executor, @Nullable CancellationSignal cancellationSignal, - @NonNull AnswerCallback<T> callback) { + @NonNull Callback<? super byte[]> callback) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } @@ -263,11 +238,9 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); + ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags); } catch (ErrnoException e) { - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } synchronized (lock) { @@ -277,27 +250,28 @@ public final class DnsResolver { } } - private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback { + private class InetAddressAnswerAccumulator implements Callback<byte[]> { private final List<InetAddress> mAllAnswers; - private ParseException mParseException; - private ErrnoException mErrnoException; - private final InetAddressAnswerCallback mUserCallback; + private int mRcode; + private DnsException mDnsException; + private final Callback<? super List<InetAddress>> mUserCallback; private final int mTargetAnswerCount; private int mReceivedAnswerCount = 0; - InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerCallback callback) { + InetAddressAnswerAccumulator(int size, + @NonNull Callback<? super List<InetAddress>> callback) { mTargetAnswerCount = size; mAllAnswers = new ArrayList<>(); mUserCallback = callback; } - private boolean maybeReportException() { - if (mErrnoException != null) { - mUserCallback.onQueryException(mErrnoException); + private boolean maybeReportError() { + if (mRcode != 0) { + mUserCallback.onAnswer(mAllAnswers, mRcode); return true; } - if (mParseException != null) { - mUserCallback.onParseException(mParseException); + if (mDnsException != null) { + mUserCallback.onError(mDnsException); return true; } return false; @@ -305,34 +279,43 @@ public final class DnsResolver { private void maybeReportAnswer() { if (++mReceivedAnswerCount != mTargetAnswerCount) return; - if (mAllAnswers.isEmpty() && maybeReportException()) return; + if (mAllAnswers.isEmpty() && maybeReportError()) return; // TODO: Do RFC6724 sort. - mUserCallback.onAnswer(mAllAnswers); - } - - @Override - public void onAnswer(@NonNull List<InetAddress> answer) { - mAllAnswers.addAll(answer); - maybeReportAnswer(); + mUserCallback.onAnswer(mAllAnswers, mRcode); } @Override - public void onParseException(@NonNull ParseException e) { - mParseException = e; + public void onAnswer(@NonNull byte[] answer, int rcode) { + // If at least one query succeeded, return an rcode of 0. + // Otherwise, arbitrarily return the first rcode received. + if (mReceivedAnswerCount == 0 || rcode == 0) { + mRcode = rcode; + } + try { + mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses()); + } catch (ParseException e) { + mDnsException = new DnsException(ERROR_PARSE, e); + } maybeReportAnswer(); } @Override - public void onQueryException(@NonNull ErrnoException e) { - mErrnoException = e; + public void onError(@NonNull DnsException error) { + mDnsException = error; maybeReportAnswer(); } } /** - * Send a DNS query with the specified name, get back a set of InetAddresses asynchronously. - * The answer will be provided asynchronously through the provided - * {@link InetAddressAnswerCallback}. + * Send a DNS query with the specified name on a network with both IPv4 and IPv6, + * get back a set of InetAddresses asynchronously. + * + * This method will examine the connection ability on given network, and query IPv4 + * and IPv6 if connection is available. + * + * If at least one query succeeded with valid answer, rcode will be 0 + * + * The answer will be provided asynchronously through the provided {@link Callback}. * * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. @@ -341,13 +324,13 @@ public final class DnsResolver { * @param executor The {@link Executor} that the callback should be executed on. * @param cancellationSignal used by the caller to signal if the query should be * cancelled. May be {@code null}. - * @param callback an {@link InetAddressAnswerCallback} which will be called to notify the + * @param callback a {@link Callback} which will be called to notify the * caller of the result of dns query. */ public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags, @NonNull @CallbackExecutor Executor executor, @Nullable CancellationSignal cancellationSignal, - @NonNull InetAddressAnswerCallback callback) { + @NonNull Callback<? super List<InetAddress>> callback) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } @@ -363,11 +346,10 @@ public final class DnsResolver { if (queryIpv6) { try { v6fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_AAAA, flags); } catch (ErrnoException e) { - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } queryCount++; @@ -377,17 +359,18 @@ public final class DnsResolver { // Avoiding gateways drop packets if queries are sent too close together try { Thread.sleep(SLEEP_TIME_MS); - } catch (InterruptedException ex) { } + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } if (queryIpv4) { try { v4fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_A, flags); } catch (ErrnoException e) { if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } queryCount++; @@ -413,34 +396,89 @@ public final class DnsResolver { } } - private <T> void registerFDListener(@NonNull Executor executor, - @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback, + /** + * Send a DNS query with the specified name and query type, get back a set of + * InetAddresses asynchronously. + * + * The answer will be provided asynchronously through the provided {@link Callback}. + * + * @param network {@link Network} specifying which network to query on. + * {@code null} for query on default network. + * @param domain domain name to query + * @param nsType dns resource record (RR) type as one of the TYPE_* constants + * @param flags flags as a combination of the FLAGS_* constants + * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. + * @param callback a {@link Callback} which will be called to notify the caller + * of the result of dns query. + */ + public void query(@Nullable Network network, @NonNull String domain, + @QueryType int nsType, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull Callback<? super List<InetAddress>> callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + final Object lock = new Object(); + final FileDescriptor queryfd; + try { + queryfd = resNetworkQuery((network != null + ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + final InetAddressAnswerAccumulator accumulator = + new InetAddressAnswerAccumulator(1, callback); + synchronized (lock) { + registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock); + if (cancellationSignal == null) return; + addCancellationSignal(cancellationSignal, queryfd, lock); + } + } + + /** + * Class to retrieve DNS response + * + * @hide + */ + public static final class DnsResponse { + public final @NonNull byte[] answerbuf; + public final int rcode; + public DnsResponse(@NonNull byte[] answerbuf, int rcode) { + this.answerbuf = answerbuf; + this.rcode = rcode; + } + } + + private void registerFDListener(@NonNull Executor executor, + @NonNull FileDescriptor queryfd, @NonNull Callback<? super byte[]> answerCallback, @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) { Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener( queryfd, FD_EVENTS, (fd, events) -> { executor.execute(() -> { + DnsResponse resp = null; + ErrnoException exception = null; synchronized (lock) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } - byte[] answerbuf = null; try { - answerbuf = resNetworkResult(fd); // Closes fd, marks it invalid. + resp = resNetworkResult(fd); // Closes fd, marks it invalid. } catch (ErrnoException e) { Log.e(TAG, "resNetworkResult:" + e.toString()); - answerCallback.onQueryException(e); - return; - } - - try { - answerCallback.onAnswer( - answerCallback.parser.parse(answerbuf)); - } catch (ParseException e) { - answerCallback.onParseException(e); + exception = e; } } + if (exception != null) { + answerCallback.onError(new DnsException(ERROR_SYSTEM, exception)); + return; + } + answerCallback.onAnswer(resp.answerbuf, resp.rcode); }); // Unregister this fd listener return 0; diff --git a/core/java/android/net/ITestNetworkManager.aidl b/core/java/android/net/ITestNetworkManager.aidl index 119a30cb2ddb..bab6ae8e7409 100644 --- a/core/java/android/net/ITestNetworkManager.aidl +++ b/core/java/android/net/ITestNetworkManager.aidl @@ -29,6 +29,7 @@ import android.os.ParcelFileDescriptor; interface ITestNetworkManager { TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs); + TestNetworkInterface createTapInterface(); void setupTestNetwork(in String iface, in IBinder binder); diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index db87c97e4fc7..c06a13269d83 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -145,9 +145,10 @@ public class NetworkUtils { /** * DNS resolver series jni method. * Read a result for the query associated with the {@code fd}. - * @return a byte array containing blob answer + * @return DnsResponse containing blob answer and rcode */ - public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException; + public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd) + throws ErrnoException; /** * DNS resolver series jni method. diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java index 9d4727a84bc0..bcfdd7ef09cc 100644 --- a/core/java/android/net/ParseException.java +++ b/core/java/android/net/ParseException.java @@ -25,12 +25,12 @@ import android.annotation.NonNull; public class ParseException extends RuntimeException { public String response; - public ParseException(@NonNull String response) { + ParseException(@NonNull String response) { super(response); this.response = response; } - public ParseException(@NonNull String response, @NonNull Throwable cause) { + ParseException(@NonNull String response, @NonNull Throwable cause) { super(response, cause); this.response = response; } 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/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java index 30e68f5b9854..84550834be07 100644 --- a/core/java/android/net/TestNetworkInterface.java +++ b/core/java/android/net/TestNetworkInterface.java @@ -27,8 +27,6 @@ import android.os.Parcelable; */ @TestApi public final class TestNetworkInterface implements Parcelable { - private static final String TAG = "TestNetworkInterface"; - private final ParcelFileDescriptor mFileDescriptor; private final String mInterfaceName; diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java index cd58e6641e51..e274005eb9d1 100644 --- a/core/java/android/net/TestNetworkManager.java +++ b/core/java/android/net/TestNetworkManager.java @@ -17,7 +17,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.TestApi; -import android.content.Context; import android.os.IBinder; import android.os.RemoteException; @@ -33,11 +32,9 @@ public class TestNetworkManager { @NonNull private static final String TAG = TestNetworkManager.class.getSimpleName(); @NonNull private final ITestNetworkManager mService; - @NonNull private final Context mContext; /** @hide */ - public TestNetworkManager(@NonNull Context context, @NonNull ITestNetworkManager service) { - mContext = Preconditions.checkNotNull(context, "missing Context"); + public TestNetworkManager(@NonNull ITestNetworkManager service) { mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager"); } @@ -88,4 +85,21 @@ public class TestNetworkManager { throw e.rethrowFromSystemServer(); } } + + /** + * Create a tap interface for testing purposes + * + * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the + * TAP interface. + * @hide + */ + @TestApi + public TestNetworkInterface createTapInterface() { + try { + return mService.createTapInterface(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } 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/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index f87abde361f3..83e19803a63b 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import com.android.internal.util.Preconditions; @@ -41,6 +42,7 @@ import java.util.concurrent.Executor; * @hide */ @SystemApi +@TestApi @SystemService(Context.BUGREPORT_SERVICE) public final class BugreportManager { private final Context mContext; diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java index 279ccae7c94f..c834781346f6 100644 --- a/core/java/android/os/BugreportParams.java +++ b/core/java/android/os/BugreportParams.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.IntDef; import android.annotation.SystemApi; +import android.annotation.TestApi; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -28,6 +29,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi +@TestApi public final class BugreportParams { private final int mMode; diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index e56b6e0a33b8..779790c09dc8 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -72,6 +72,14 @@ public class GraphicsEnvironment { private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message"; private static final String GAME_DRIVER_WHITELIST_ALL = "*"; + // GAME_DRIVER_ALL_APPS + // 0: Default (Invalid values fallback to default as well) + // 1: All apps use Game Driver + // 2: All apps use system graphics driver + private static final int GAME_DRIVER_GLOBAL_OPT_IN_DEFAULT = 0; + private static final int GAME_DRIVER_GLOBAL_OPT_IN_ALL = 1; + private static final int GAME_DRIVER_GLOBAL_OPT_IN_NONE = 2; + private ClassLoader mClassLoader; private String mLayerPath; private String mDebugLayerPath; @@ -97,6 +105,65 @@ public class GraphicsEnvironment { } /** + * Allow to query whether an application will use Game Driver. + */ + public static boolean shouldUseGameDriver(Context context, Bundle coreSettings, + ApplicationInfo applicationInfo) { + final String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER); + if (driverPackageName == null || driverPackageName.isEmpty()) { + return false; + } + + // To minimize risk of driver updates crippling the device beyond user repair, never use an + // updated driver for privileged or non-updated system apps. Presumably pre-installed apps + // were tested thoroughly with the pre-installed driver. + if (applicationInfo.isPrivilegedApp() || (applicationInfo.isSystemApp() + && !applicationInfo.isUpdatedSystemApp())) { + if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app"); + return false; + } + final ContentResolver contentResolver = context.getContentResolver(); + final String packageName = applicationInfo.packageName; + final int globalOptIn; + if (coreSettings != null) { + globalOptIn = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0); + } else { + globalOptIn = Settings.Global.getInt(contentResolver, + Settings.Global.GAME_DRIVER_ALL_APPS, 0); + } + if (globalOptIn == GAME_DRIVER_GLOBAL_OPT_IN_ALL) { + return true; + } + if (globalOptIn == GAME_DRIVER_GLOBAL_OPT_IN_NONE) { + return false; + } + + // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS + if (getGlobalSettingsString(contentResolver, coreSettings, + Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) { + return false; + } + final boolean isOptIn = getGlobalSettingsString(contentResolver, coreSettings, + Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName); + final List<String> whitelist = getGlobalSettingsString(contentResolver, coreSettings, + Settings.Global.GAME_DRIVER_WHITELIST); + if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0 + && !whitelist.contains(packageName)) { + return false; + } + + // If the application is not opted-in, then check whether it's on the blacklist, + // terminate early if it's on the blacklist and fallback to system driver. + if (!isOptIn + && getGlobalSettingsString(contentResolver, coreSettings, + Settings.Global.GAME_DRIVER_BLACKLIST) + .contains(packageName)) { + return false; + } + return true; + } + + /** * Check whether application is debuggable */ private static boolean isDebuggable(Context context) { @@ -657,59 +724,10 @@ public class GraphicsEnvironment { return false; } - // To minimize risk of driver updates crippling the device beyond user repair, never use an - // updated driver for privileged or non-updated system apps. Presumably pre-installed apps - // were tested thoroughly with the pre-installed driver. - final ApplicationInfo ai = context.getApplicationInfo(); - if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) { - if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app"); - return false; - } - - // GAME_DRIVER_ALL_APPS - // 0: Default (Invalid values fallback to default as well) - // 1: All apps use Game Driver - // 2: All apps use system graphics driver - final int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0); - if (gameDriverAllApps == 2) { - if (DEBUG) { - Log.w(TAG, "Game Driver is turned off on this device"); - } + if (!shouldUseGameDriver(context, coreSettings, context.getApplicationInfo())) { return false; } - if (gameDriverAllApps != 1) { - // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS - if (getGlobalSettingsString(null, coreSettings, - Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) { - if (DEBUG) { - Log.w(TAG, packageName + " opts out from Game Driver."); - } - return false; - } - final boolean isOptIn = - getGlobalSettingsString(null, coreSettings, - Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName); - final List<String> whitelist = getGlobalSettingsString(null, coreSettings, - Settings.Global.GAME_DRIVER_WHITELIST); - if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0 - && !whitelist.contains(packageName)) { - if (DEBUG) { - Log.w(TAG, packageName + " is not on the whitelist."); - } - return false; - } - - // If the application is not opted-in and check whether it's on the blacklist, - // terminate early if it's on the blacklist and fallback to system driver. - if (!isOptIn - && getGlobalSettingsString(null, coreSettings, - Settings.Global.GAME_DRIVER_BLACKLIST) - .contains(ai.packageName)) { - return false; - } - } - final String abi = chooseAbi(driverAppInfo); if (abi == null) { if (DEBUG) { diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index a7ac7a1fd689..fb35db11027b 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -513,6 +513,7 @@ public class Process { * @param packageName null-ok the name of the package this process belongs to. * @param packagesForUid null-ok all the packages with the same uid as this process. * @param zygoteArgs Additional arguments to supply to the zygote process. + * @param useSystemGraphicsDriver whether the process uses system graphics driver. * * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure @@ -532,12 +533,13 @@ public class Process { @Nullable String packageName, @Nullable String[] packagesForUid, @Nullable String sandboxId, - @Nullable String[] zygoteArgs) { + @Nullable String[] zygoteArgs, + boolean useSystemGraphicsDriver) { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, packagesForUid, sandboxId, /*useUnspecializedAppProcessPool=*/ true, - zygoteArgs); + zygoteArgs, useSystemGraphicsDriver); } /** @hide */ @@ -554,12 +556,13 @@ public class Process { @Nullable String packageName, @Nullable String[] packagesForUid, @Nullable String sandboxId, - @Nullable String[] zygoteArgs) { + @Nullable String[] zygoteArgs, + boolean useSystemGraphicsDriver) { return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, packagesForUid, sandboxId, /*useUnspecializedAppProcessPool=*/ false, - zygoteArgs); + zygoteArgs, useSystemGraphicsDriver); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index ab19fd6e8ca1..b7789c0c2857 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -308,6 +308,7 @@ public class ZygoteProcess { * @param packageName null-ok the name of the package this process belongs to. * @param packagesForUid null-ok all the packages with the same uid as this process. * @param zygoteArgs Additional arguments to supply to the zygote process. + * @param useSystemGraphicsDriver whether the process uses system graphics driver. * * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure @@ -326,7 +327,8 @@ public class ZygoteProcess { @Nullable String[] packagesForUid, @Nullable String sandboxId, boolean useUsapPool, - @Nullable String[] zygoteArgs) { + @Nullable String[] zygoteArgs, + boolean useSystemGraphicsDriver) { // TODO (chriswailes): Is there a better place to check this value? if (fetchUsapPoolEnabledPropWithMinInterval()) { informZygotesOfUsapPoolStatus(); diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 847b8e48b296..02f99258395c 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -16,6 +16,7 @@ package android.preference; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager; import android.content.BroadcastReceiver; @@ -27,8 +28,8 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; -import android.media.audiopolicy.AudioProductStrategies; -import android.media.audiopolicy.AudioVolumeGroups; +import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; @@ -67,7 +68,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private static final int MSG_GROUP_VOLUME_CHANGED = 1; private final Handler mVolumeHandler = new VolumeHandler(); - private final AudioProductStrategies mAudioProductStrategies; private AudioAttributes mAttributes; private int mVolumeGroupId; @@ -161,11 +161,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } mZenMode = mNotificationManager.getZenMode(); - mAudioProductStrategies = mAudioManager.getAudioProductStrategies(); - if (mAudioProductStrategies.size() > 0) { - mVolumeGroupId = mAudioProductStrategies.getVolumeGroupIdForLegacyStreamType( - mStreamType); - mAttributes = mAudioProductStrategies.getAudioAttributesForLegacyStreamType( + if (hasAudioProductStrategies()) { + mVolumeGroupId = getVolumeGroupIdForLegacyStreamType(mStreamType); + mAttributes = getAudioAttributesForLegacyStreamType( mStreamType); } @@ -190,6 +188,40 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mDefaultUri = defaultUri; } + private boolean hasAudioProductStrategies() { + return AudioManager.getAudioProductStrategies().size() > 0; + } + + private int getVolumeGroupIdForLegacyStreamType(int streamType) { + for (final AudioProductStrategy productStrategy : + AudioManager.getAudioProductStrategies()) { + int volumeGroupId = productStrategy.getVolumeGroupIdForLegacyStreamType(streamType); + if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { + return volumeGroupId; + } + } + + return AudioManager.getAudioProductStrategies().stream() + .map(strategy -> strategy.getVolumeGroupIdForAudioAttributes( + AudioProductStrategy.sDefaultAttributes)) + .filter(volumeGroupId -> volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) + .findFirst() + .orElse(AudioVolumeGroup.DEFAULT_VOLUME_GROUP); + } + + private @NonNull AudioAttributes getAudioAttributesForLegacyStreamType(int streamType) { + for (final AudioProductStrategy productStrategy : + AudioManager.getAudioProductStrategies()) { + AudioAttributes aa = productStrategy.getAudioAttributesForLegacyStreamType(streamType); + if (aa != null) { + return aa; + } + } + return new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) + .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); + } + private static boolean isNotificationOrRing(int stream) { return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION; } @@ -329,7 +361,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba postStopSample(); mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); mReceiver.setListening(false); - if (mAudioProductStrategies.size() > 0) { + if (hasAudioProductStrategies()) { unregisterVolumeGroupCb(); } mSeekBar.setOnSeekBarChangeListener(null); @@ -349,7 +381,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba System.getUriFor(System.VOLUME_SETTINGS_INT[mStreamType]), false, mVolumeObserver); mReceiver.setListening(true); - if (mAudioProductStrategies.size() > 0) { + if (hasAudioProductStrategies()) { registerVolumeGroupCb(); } } @@ -507,7 +539,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); - if (mAudioProductStrategies.size() == 0) { + if (hasAudioProductStrategies()) { updateVolumeSlider(streamType, streamValue); } } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { @@ -519,13 +551,12 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); - if (mAudioProductStrategies.size() == 0) { + if (hasAudioProductStrategies()) { int streamVolume = mAudioManager.getStreamVolume(streamType); updateVolumeSlider(streamType, streamVolume); } else { - int volumeGroup = mAudioProductStrategies.getVolumeGroupIdForLegacyStreamType( - streamType); - if (volumeGroup != AudioVolumeGroups.DEFAULT_VOLUME_GROUP + int volumeGroup = getVolumeGroupIdForLegacyStreamType(streamType); + if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP && volumeGroup == mVolumeGroupId) { int streamVolume = mAudioManager.getStreamVolume(streamType); updateVolumeSlider(streamType, streamVolume); @@ -558,14 +589,14 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } private void registerVolumeGroupCb() { - if (mVolumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { mAudioManager.registerVolumeGroupCallback(Runnable::run, mVolumeGroupCallback); mLastProgress = mAudioManager.getVolumeIndexForAttributes(mAttributes); } } private void unregisterVolumeGroupCb() { - if (mVolumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { mAudioManager.unregisterVolumeGroupCallback(mVolumeGroupCallback); } } @@ -578,7 +609,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba case MSG_GROUP_VOLUME_CHANGED: int group = (int) args.arg1; if (mVolumeGroupId != group - || mVolumeGroupId == AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + || mVolumeGroupId == AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { return; } updateSlider(); 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 6326f2e6b2bb..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). @@ -8164,6 +8180,13 @@ public final class Settings { BOOLEAN_VALIDATOR; /** + * Whether or not debugging is enabled. + * @hide + */ + public static final String BIOMETRIC_DEBUG_ENABLED = + "biometric_debug_enabled"; + + /** * Whether the assist gesture should be enabled. * * @hide @@ -8790,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, @@ -8835,6 +8857,7 @@ public final class Settings { SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_CALL_GESTURE_COUNT, SILENCE_TIMER_GESTURE_COUNT, + DARK_MODE_DIALOG_SEEN }; /** @@ -8957,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); @@ -9017,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/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java index 4088ce8ea4b0..30c4e900f83c 100644 --- a/core/java/android/service/textclassifier/TextClassifierService.java +++ b/core/java/android/service/textclassifier/TextClassifierService.java @@ -358,6 +358,7 @@ public abstract class TextClassifierService extends Service { /** * Returns the platform's default TextClassifier implementation. */ + @NonNull public static TextClassifier getDefaultTextClassifierImplementation(@NonNull Context context) { final TextClassificationManager tcm = context.getSystemService(TextClassificationManager.class); 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/util/DocumentsStatsLog.java b/core/java/android/util/DocumentsStatsLog.java deleted file mode 100644 index a67bbde8b30b..000000000000 --- a/core/java/android/util/DocumentsStatsLog.java +++ /dev/null @@ -1,169 +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 android.util; - -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.provider.DocumentsContract; -import android.provider.DocumentsProvider; - -/** - * DocumentsStatsLog provides APIs to send DocumentsUI related events to statsd. - * @hide - */ -@SystemApi -public class DocumentsStatsLog { - - private DocumentsStatsLog() {} - - /** - * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up. - * - * @param action action that launches DocumentsUI. - * @param hasInitialUri is DocumentsUI launched with - * {@link DocumentsContract#EXTRA_INITIAL_URI}. - * @param mimeType the requested mime type. - * @param rootUri the resolved rootUri, or {@code null} if the provider doesn't - * support {@link DocumentsProvider#findDocumentPath(String, String)} - */ - public static void logActivityLaunch( - int action, boolean hasInitialUri, int mimeType, int rootUri) { - StatsLog.write(StatsLog.DOCS_UI_LAUNCH_REPORTED, action, hasInitialUri, mimeType, rootUri); - } - - /** - * Logs root visited event. - * - * @param scope whether it's in FILES or PICKER mode. - * @param root the root that user visited - */ - public static void logRootVisited(int scope, int root) { - StatsLog.write(StatsLog.DOCS_UI_ROOT_VISITED, scope, root); - } - - /** - * Logs file operation stats. Call this when a file operation has completed. - * - * @param provider whether it's system or external provider - * @param fileOp the file operation - */ - public static void logFileOperation(int provider, int fileOp) { - StatsLog.write(StatsLog.DOCS_UI_PROVIDER_FILE_OP, provider, fileOp); - } - - /** - * Logs file operation stats. Call this when a copy/move operation has completed with a specific - * mode. - * - * @param fileOp copy or move file operation - * @param mode the mode for copy and move operation - */ - public static void logFileOperationCopyMoveMode(int fileOp, int mode) { - StatsLog.write(StatsLog.DOCS_UI_FILE_OP_COPY_MOVE_MODE_REPORTED, fileOp, mode); - } - - /** - * Logs file sub operation stats. Call this when a file operation has failed. - * - * @param authority the authority of the source document - * @param subOp the sub-file operation - */ - public static void logFileOperationFailure(int authority, int subOp) { - StatsLog.write(StatsLog.DOCS_UI_FILE_OP_FAILURE, authority, subOp); - } - - /** - * Logs the cancellation of a file operation. Call this when a job is canceled - * - * @param fileOp the file operation. - */ - public static void logFileOperationCanceled(int fileOp) { - StatsLog.write(StatsLog.DOCS_UI_FILE_OP_CANCELED, fileOp); - } - - /** - * Logs startup time in milliseconds. - * - * @param startupMs - */ - public static void logStartupMs(int startupMs) { - StatsLog.write(StatsLog.DOCS_UI_STARTUP_MS, startupMs); - } - - /** - * Logs the action that was started by user. - * - * @param userAction - */ - public static void logUserAction(int userAction) { - StatsLog.write(StatsLog.DOCS_UI_USER_ACTION_REPORTED, userAction); - } - - /** - * Logs the invalid type when invalid scoped access is requested. - * - * @param type the type of invalid scoped access request. - */ - public static void logInvalidScopedAccessRequest(int type) { - StatsLog.write(StatsLog.DOCS_UI_INVALID_SCOPED_ACCESS_REQUEST, type); - } - - /** - * Logs the package name that launches docsui picker mode. - * - * @param packageName - */ - public static void logPickerLaunchedFrom(@Nullable String packageName) { - StatsLog.write(StatsLog.DOCS_UI_PICKER_LAUNCHED_FROM_REPORTED, packageName); - } - - /** - * Logs the search type. - * - * @param searchType - */ - public static void logSearchType(int searchType) { - StatsLog.write(StatsLog.DOCS_UI_SEARCH_TYPE_REPORTED, searchType); - } - - /** - * Logs the search mode. - * - * @param searchMode - */ - public static void logSearchMode(int searchMode) { - StatsLog.write(StatsLog.DOCS_UI_SEARCH_MODE_REPORTED, searchMode); - } - - /** - * Logs the pick result information. - * - * @param actionCount total user action count during pick process. - * @param duration total time spent on pick process. - * @param fileCount number of picked files. - * @param isSearching are the picked files found by search. - * @param root the root where the picked files located. - * @param mimeType the mime type of the picked file. Only for single-select case. - * @param repeatedlyPickTimes number of times that the file has been picked before. Only for - * single-select case. - */ - public static void logFilePick(int actionCount, long duration, int fileCount, - boolean isSearching, int root, int mimeType, int repeatedlyPickTimes) { - StatsLog.write(StatsLog.DOCS_UI_PICK_RESULT_REPORTED, actionCount, duration, fileCount, - isSearching, root, mimeType, repeatedlyPickTimes); - } -} diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index feff9db1a63e..f2aaeaddef97 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -63,7 +63,6 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(FORCE_GLOBAL_ACTIONS_GRID_ENABLED, "false"); DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true"); DEFAULT_FLAGS.put(PIXEL_WALLPAPER_CATEGORY_SWITCH, "false"); - DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "true"); DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false"); } diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index dd22a26d61af..cfc092cb78e8 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -187,26 +187,6 @@ public final class StatsLog extends StatsLogInternal { } /** - * Add a log to the stats log. - * - * @param id The id of the atom - * @param params The parameters of the atom's message. - */ - public static void write(int id, @NonNull Object... params) { - switch (id) { - case PERMISSION_GRANT_REQUEST_RESULT_REPORTED: - write(id, (long) params[0], (int) params[1], (String) params[2], (String) params[3], - (boolean) params[4], (int) params[5]); - break; - case DATA_STALL_EVENT: - // Refer to the defintion in frameworks/base/cmds/statsd/src/atoms.proto. - write(id, (int) params[0], (int) params[1], (int) params[2], (byte[]) params[3], - (byte[]) params[4], (byte[]) params[5]); - break; - } - } - - /** * Write an event to stats log using the raw format. * * @param buffer The encoded buffer of data to write.. diff --git a/core/java/android/util/StatsLogAtoms.java b/core/java/android/util/StatsLogAtoms.java deleted file mode 100644 index 4780cb58ca06..000000000000 --- a/core/java/android/util/StatsLogAtoms.java +++ /dev/null @@ -1,122 +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 android.util; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.annotation.IntDef; -import android.annotation.SystemApi; - -import java.lang.annotation.Retention; - -/** - * Exposed stats logs atom ids. - * - * @hide - */ -@SystemApi -public class StatsLogAtoms { - private StatsLogAtoms() { - } - - /** - * Information about a permission grant request - * - * Usage: {@code StatsLog.write(PERMISSION_GRANT_REQUEST_RESULT_REPORTED, long request_id, - * int requesting_uid, String requesting_package_name, String permission_name, - * boolean is_implicit, @PermissionGrantRequestResultReported_Result int result)} - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED; - - @Retention(SOURCE) - @IntDef(prefix = "PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__", - value = {PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED, - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED, - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED, - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED, - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED, - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED, - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE, - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED}) - public @interface PermissionGrantRequestResultReported_Result {} - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission request was ignored - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission request was ignored because it was user fixed - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission request was ignored because it was policy fixed - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission request was ignored because it was restricted - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission was granted by user action - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission was automatically granted - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission was denied by user action - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission was denied with prejudice by the user - */ - public static final int - PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE = - StatsLogInternal - .PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE; - - /** - * Possible value of {@link PermissionGrantRequestResultReported_Result}: - * permission was automatically denied - */ - public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED = - StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED; -} diff --git a/core/java/android/view/GestureExclusionTracker.java b/core/java/android/view/GestureExclusionTracker.java index 8eccc04fa647..6fcdd714f827 100644 --- a/core/java/android/view/GestureExclusionTracker.java +++ b/core/java/android/view/GestureExclusionTracker.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; +import com.android.internal.util.Preconditions; + import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; @@ -31,6 +33,8 @@ import java.util.List; */ class GestureExclusionTracker { private boolean mGestureExclusionViewsChanged = false; + private boolean mRootGestureExclusionRectsChanged = false; + private List<Rect> mRootGestureExclusionRects = Collections.emptyList(); private List<GestureExclusionViewInfo> mGestureExclusionViewInfos = new ArrayList<>(); private List<Rect> mGestureExclusionRects = Collections.emptyList(); @@ -59,9 +63,9 @@ class GestureExclusionTracker { @Nullable public List<Rect> computeChangedRects() { - boolean changed = false; + boolean changed = mRootGestureExclusionRectsChanged; final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator(); - final List<Rect> rects = new ArrayList<>(); + final List<Rect> rects = new ArrayList<>(mRootGestureExclusionRects); while (i.hasNext()) { final GestureExclusionViewInfo info = i.next(); switch (info.update()) { @@ -79,6 +83,7 @@ class GestureExclusionTracker { } if (changed || mGestureExclusionViewsChanged) { mGestureExclusionViewsChanged = false; + mRootGestureExclusionRectsChanged = false; if (!mGestureExclusionRects.equals(rects)) { mGestureExclusionRects = rects; return rects; @@ -87,6 +92,17 @@ class GestureExclusionTracker { return null; } + public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { + Preconditions.checkNotNull(rects, "rects must not be null"); + mRootGestureExclusionRects = rects; + mRootGestureExclusionRectsChanged = true; + } + + @NonNull + public List<Rect> getRootSystemGestureExclusionRects() { + return mRootGestureExclusionRects; + } + private static class GestureExclusionViewInfo { public static final int CHANGED = 0; public static final int UNCHANGED = 1; diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index 2ba1e016e03d..d415387808dd 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -85,6 +85,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { @Override public void onWindowFocusLost() { mHasWindowFocus = false; + getImm().unregisterImeConsumer(this); } /** 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/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b5ad908e5ea5..d67c8847f3bc 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -90,8 +90,8 @@ public final class SurfaceControl implements Parcelable { private static native ScreenshotGraphicBuffer nativeScreenshot(IBinder displayToken, Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation, boolean captureSecureLayers); - private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder layerHandleToken, - Rect sourceCrop, float frameScale, IBinder[] excludeLayers); + private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder displayToken, + IBinder layerHandleToken, Rect sourceCrop, float frameScale, IBinder[] excludeLayers); private static native long nativeCreateTransaction(); private static native long nativeGetNativeTransactionFinalizer(); @@ -1998,7 +1998,8 @@ public final class SurfaceControl implements Parcelable { */ public static ScreenshotGraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop, float frameScale) { - return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale, null); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + return nativeCaptureLayers(displayToken, layerHandleToken, sourceCrop, frameScale, null); } /** @@ -2007,7 +2008,8 @@ public final class SurfaceControl implements Parcelable { */ public static ScreenshotGraphicBuffer captureLayersExcluding(IBinder layerHandleToken, Rect sourceCrop, float frameScale, IBinder[] exclude) { - return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale, exclude); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + return nativeCaptureLayers(displayToken, layerHandleToken, sourceCrop, frameScale, exclude); } /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index dfa51fff0a6b..096c988c8cf1 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}. @@ -12134,14 +11648,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * When screen readers (one type of accessibility tool) decide what should be read to the - * user, they typically look for input focusable ({@link #isFocusable()}) parents of - * non-focusable text items, and read those focusable parents and their non-focusable children - * as a unit. In some situations, this behavior is desirable for views that should not take - * input focus. Setting an item to be screen reader focusable requests that the view be - * treated as a unit by screen readers without any effect on input focusability. The default - * value of {@code false} lets screen readers use other signals, like focusable, to determine - * how to group items. + * Sets whether this View should be a focusable element for screen readers + * and include non-focusable Views from its subtree when providing feedback. + * <p> + * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, + * but does not impact input focus behavior. * * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader * accessibility tools. @@ -13753,7 +13264,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void dispatchStartTemporaryDetach() { mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); onStartTemporaryDetach(); } @@ -13780,7 +13290,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyFocusChangeToInputMethodManager(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } /** @@ -14372,8 +13881,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } } - - notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); } /** @@ -17998,7 +17505,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final int scrollX = mScrollX; final int scrollY = mScrollY; invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, - dirty.right - scrollX, dirty.bottom - scrollY, true); + dirty.right - scrollX, dirty.bottom - scrollY, true, false); } /** @@ -18024,7 +17531,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void invalidate(int l, int t, int r, int b) { final int scrollX = mScrollX; final int scrollY = mScrollY; - invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true); + invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); } /** @@ -18054,10 +17561,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @UnsupportedAppUsage public void invalidate(boolean invalidateCache) { - invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache); + invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); } - void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache) { + void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, + boolean fullInvalidate) { if (mGhostView != null) { mGhostView.invalidate(true); return; @@ -18068,15 +17576,16 @@ 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) || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED - || isOpaque() != mLastIsOpaque) { - mLastIsOpaque = isOpaque(); - mPrivateFlags &= ~PFLAG_DRAWN; + || (fullInvalidate && isOpaque() != mLastIsOpaque)) { + if (fullInvalidate) { + mLastIsOpaque = isOpaque(); + mPrivateFlags &= ~PFLAG_DRAWN; + } mPrivateFlags |= PFLAG_DIRTY; @@ -20076,7 +19585,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, needGlobalAttributesUpdate(false); notifyEnterOrExitForAutoFillIfNeeded(true); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @@ -20126,7 +19634,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** @@ -22439,8 +21946,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; notifyEnterOrExitForAutoFillIfNeeded(true); } - - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } private boolean hasParentWantsFocus() { @@ -22621,7 +22126,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Override public void invalidateDrawable(@NonNull Drawable drawable) { if (verifyDrawable(drawable)) { - invalidate(); + final Rect dirty = drawable.getDirtyBounds(); + final int scrollX = mScrollX; + final int scrollY = mScrollY; + + invalidate(dirty.left + scrollX, dirty.top + scrollY, + dirty.right + scrollX, dirty.bottom + scrollY); rebuildOutline(); } } @@ -28642,23 +28152,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. * @@ -28676,31 +28169,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..7ad118e760d8 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) { @@ -3986,6 +3829,24 @@ public final class ViewRootImpl implements ViewParent, } /** + * Set the root-level system gesture exclusion rects. These are added to those provided by + * the root's view hierarchy. + */ + public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { + mGestureExclusionTracker.setRootSystemGestureExclusionRects(rects); + mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + } + + /** + * Returns the root-level system gesture exclusion rects. These do not include those provided by + * the root's view hierarchy. + */ + @NonNull + public List<Rect> getRootSystemGestureExclusionRects() { + return mGestureExclusionTracker.getRootSystemGestureExclusionRects(); + } + + /** * Requests that the root render node is invalidated next time we perform a draw, such that * {@link WindowCallbacks#onPostDraw} gets called. */ diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index a9463e998bbb..b0ec6210d828 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -48,6 +48,7 @@ import android.transition.Transition; import android.transition.TransitionManager; import android.view.accessibility.AccessibilityEvent; +import java.util.Collections; import java.util.List; /** @@ -2340,10 +2341,11 @@ public abstract class Window { * <p>When the status bar color has a non-zero alpha value, the value of this * property has no effect. * - * @see android.R.attr#ensureStatusBarContrastWhenTransparent - * @hide pending API + * @see android.R.attr#ensuringStatusBarContrastWhenTransparent + * @see #isEnsuringStatusBarContrastWhenTransparent + * @see #setStatusBarColor */ - public void setEnsureStatusBarContrastWhenTransparent(boolean ensureContrast) { + public void setEnsuringStatusBarContrastWhenTransparent(boolean ensureContrast) { } /** @@ -2353,11 +2355,12 @@ public abstract class Window { * <p>When the status bar color has a non-zero alpha value, the value of this * property has no effect. * - * @see android.R.attr#ensureStatusBarContrastWhenTransparent * @return true, if the system is ensuring contrast, false otherwise. - * @hide pending API + * @see android.R.attr#ensuringStatusBarContrastWhenTransparent + * @see #setEnsuringStatusBarContrastWhenTransparent + * @see #setStatusBarColor */ - public boolean isEnsureStatusBarContrastWhenTransparent() { + public boolean isEnsuringStatusBarContrastWhenTransparent() { return false; } @@ -2372,10 +2375,11 @@ public abstract class Window { * <p>When the navigation bar color has a non-zero alpha value, the value of this * property has no effect. * - * @see android.R.attr#ensureNavigationBarContrastWhenTransparent - * @hide pending API + * @see android.R.attr#ensuringNavigationBarContrastWhenTransparent + * @see #isEnsuringNavigationBarContrastWhenTransparent + * @see #setNavigationBarColor */ - public void setEnsureNavigationBarContrastWhenTransparent(boolean ensureContrast) { + public void setEnsuringNavigationBarContrastWhenTransparent(boolean ensureContrast) { } /** @@ -2386,13 +2390,61 @@ public abstract class Window { * property has no effect. * * @return true, if the system is ensuring contrast, false otherwise. - * @see android.R.attr#ensureNavigationBarContrastWhenTransparent - * @hide pending API + * @see android.R.attr#ensuringNavigationBarContrastWhenTransparent + * @see #setEnsuringNavigationBarContrastWhenTransparent + * @see #setNavigationBarColor */ - public boolean isEnsureNavigationBarContrastWhenTransparent() { + public boolean isEnsuringNavigationBarContrastWhenTransparent() { return false; } + /** + * Sets a list of areas within this window's coordinate space where the system should not + * intercept touch or other pointing device gestures. + * + * <p>This method should be used by apps that make use of + * {@link #takeSurface(SurfaceHolder.Callback2)} and do not have a view hierarchy available. + * Apps that do have a view hierarchy should use + * {@link View#setSystemGestureExclusionRects(List)} instead. This method does not modify or + * replace the gesture exclusion rects populated by individual views in this window's view + * hierarchy using {@link View#setSystemGestureExclusionRects(List)}.</p> + * + * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture + * input in order to function correctly in the presence of global system gestures that may + * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures + * to provide system-level navigation functionality, a view such as a navigation drawer + * container can mark the left (or starting) edge of itself as requiring gesture capture + * priority using this API. The system may then choose to relax its own gesture recognition + * to allow the app to consume the user's gesture. It is not necessary for an app to register + * exclusion rects for broadly spanning regions such as the entirety of a + * <code>ScrollView</code> or for simple press and release click targets such as + * <code>Button</code>. Mark an exclusion rect when interacting with a view requires + * a precision touch gesture in a small area in either the X or Y dimension, such as + * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> + * + * <p>Do not modify the provided list after this method is called.</p> + * + * @param rects A list of precision gesture regions that this window needs to function correctly + */ + @SuppressWarnings("unused") + public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { + throw new UnsupportedOperationException("window does not support gesture exclusion rects"); + } + + /** + * Retrieve the list of areas within this window's coordinate space where the system should not + * intercept touch or other pointing device gestures. This is the list as set by + * {@link #setSystemGestureExclusionRects(List)} or an empty list if + * {@link #setSystemGestureExclusionRects(List)} has not been called. It does not include + * exclusion rects set by this window's view hierarchy. + * + * @return a list of system gesture exclusion rects specific to this window + */ + @NonNull + public List<Rect> getSystemGestureExclusionRects() { + return Collections.emptyList(); + } + /** @hide */ public void setTheme(int resId) { } 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..26454c055932 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 { @@ -343,15 +343,6 @@ public final class ContentCaptureManager { private MainContentCaptureSession mMainSession; /** @hide */ - public interface ContentCaptureClient { - /** - * Gets the component name of the client. - */ - @NonNull - ComponentName contentCaptureClientGetComponentName(); - } - - /** @hide */ public ContentCaptureManager(@NonNull Context context, @NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) { mContext = Preconditions.checkNotNull(context, "context cannot be null"); @@ -578,16 +569,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/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 5e00425407ba..fd73856bf79b 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1951,6 +1951,23 @@ public final class InputMethodManager { } /** + * Unregister for IME state callbacks and applying visibility in + * {@link android.view.ImeInsetsSourceConsumer}. + * @hide + */ + public void unregisterImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) { + if (imeInsetsConsumer == null) { + throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null."); + } + + synchronized (mH) { + if (mImeInsetsConsumer == imeInsetsConsumer) { + mImeInsetsConsumer = null; + } + } + } + + /** * Call showSoftInput with currently focused view. * @return {@code true} if IME can be shown. * @hide 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/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java index 7b236747bae6..11e0e2ca072c 100644 --- a/core/java/android/view/textclassifier/ExtrasUtils.java +++ b/core/java/android/view/textclassifier/ExtrasUtils.java @@ -36,6 +36,7 @@ import java.util.List; // TODO: Make this a TestApi for CTS testing. public final class ExtrasUtils { + // Keys for response objects. private static final String SERIALIZED_ENTITIES_DATA = "serialized-entities-data"; private static final String ENTITIES_EXTRAS = "entities-extras"; private static final String ACTION_INTENT = "action-intent"; @@ -48,6 +49,10 @@ public final class ExtrasUtils { private static final String TEXT_LANGUAGES = "text-languages"; private static final String ENTITIES = "entities"; + // Keys for request objects. + private static final String IS_SERIALIZED_ENTITY_DATA_ENABLED = + "is-serialized-entity-data-enabled"; + private ExtrasUtils() {} /** @@ -308,7 +313,23 @@ public final class ExtrasUtils { /** * Returns a list of entities contained in the {@code extra}. */ + @Nullable public static List<Bundle> getEntities(Bundle container) { return container.getParcelableArrayList(ENTITIES); } + + /** + * Whether the annotator should populate serialized entity data into the result object. + */ + public static boolean isSerializedEntityDataEnabled(TextLinks.Request request) { + return request.getExtras().getBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED); + } + + /** + * To indicate whether the annotator should populate serialized entity data in the result + * object. + */ + public static void putIsSerializedEntityDataEnabled(Bundle bundle, boolean isEnabled) { + bundle.putBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED, isEnabled); + } } diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java index 236f89bf921a..d3d61a7460c7 100644 --- a/core/java/android/view/textclassifier/TextClassifierEvent.java +++ b/core/java/android/view/textclassifier/TextClassifierEvent.java @@ -19,6 +19,7 @@ package android.view.textclassifier; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.icu.util.ULocale; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -30,54 +31,65 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** - * A text classifier event. + * This class represents events that are sent by components to the {@link TextClassifier} to report + * something of note that relates to a feature powered by the TextClassifier. The TextClassifier may + * log these events or use them to improve future responses to queries. + * <p> + * Each categories of the events have their own subclass. Events of each types has an associated + * set of related properties. You can find the specification of them in the subclasses. */ -// TODO: Comprehensive javadoc. -public final class TextClassifierEvent implements Parcelable { +public abstract class TextClassifierEvent implements Parcelable { - public static final @android.annotation.NonNull Creator<TextClassifierEvent> CREATOR = new Creator<TextClassifierEvent>() { - @Override - public TextClassifierEvent createFromParcel(Parcel in) { - return readFromParcel(in); - } - - @Override - public TextClassifierEvent[] newArray(int size) { - return new TextClassifierEvent[size]; - } - }; + private static final int PARCEL_TOKEN_TEXT_SELECTION_EVENT = 1; + private static final int PARCEL_TOKEN_TEXT_LINKIFY_EVENT = 2; + private static final int PARCEL_TOKEN_CONVERSATION_ACTION_EVENT = 3; + private static final int PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT = 4; /** @hide **/ @Retention(RetentionPolicy.SOURCE) - @IntDef({CATEGORY_UNDEFINED, CATEGORY_SELECTION, CATEGORY_LINKIFY, + @IntDef({CATEGORY_SELECTION, CATEGORY_LINKIFY, CATEGORY_CONVERSATION_ACTIONS, CATEGORY_LANGUAGE_DETECTION}) public @interface Category { // For custom event categories, use range 1000+. } - /** Undefined category */ - public static final int CATEGORY_UNDEFINED = 0; - /** Smart selection */ + + /** + * Smart selection + * + * @see TextSelectionEvent + */ public static final int CATEGORY_SELECTION = 1; - /** Linkify */ + /** + * Linkify + * + * @see TextLinkifyEvent + */ public static final int CATEGORY_LINKIFY = 2; - /** Conversation actions */ + /** + * Conversation actions + * + * @see ConversationActionsEvent + */ public static final int CATEGORY_CONVERSATION_ACTIONS = 3; - /** Language detection */ + /** + * Language detection + * + * @see LanguageDetectionEvent + */ public static final int CATEGORY_LANGUAGE_DETECTION = 4; /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef({TYPE_UNDEFINED, TYPE_SELECTION_STARTED, TYPE_SELECTION_MODIFIED, - TYPE_SMART_SELECTION_SINGLE, TYPE_SMART_SELECTION_MULTI, TYPE_AUTO_SELECTION, - TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION, - TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION, - TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL, - TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED}) + @IntDef({TYPE_SELECTION_STARTED, TYPE_SELECTION_MODIFIED, + TYPE_SMART_SELECTION_SINGLE, TYPE_SMART_SELECTION_MULTI, TYPE_AUTO_SELECTION, + TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION, + TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION, + TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL, + TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED}) public @interface Type { // For custom event types, use range 1,000,000+. } - /** User started a new selection. */ - public static final int TYPE_UNDEFINED = 0; + /** User started a new selection. */ public static final int TYPE_SELECTION_STARTED = 1; /** User modified an existing selection. */ @@ -119,63 +131,49 @@ public final class TextClassifierEvent implements Parcelable { /** TextClassifier generated some actions */ public static final int TYPE_ACTIONS_GENERATED = 20; - @Category private final int mEventCategory; - @Type private final int mEventType; - @Nullable private final String[] mEntityTypes; - @Nullable private final TextClassificationContext mEventContext; - @Nullable private final String mResultId; + @Category + private final int mEventCategory; + @Type + private final int mEventType; + @Nullable + private final String[] mEntityTypes; + @Nullable + private final TextClassificationContext mEventContext; + @Nullable + private final String mResultId; private final int mEventIndex; - private final long mEventTime; + private final float[] mScores; + @Nullable + private final String mModelName; + private final int[] mActionIndices; private final Bundle mExtras; - // Smart selection. - private final int mRelativeWordStartIndex; - private final int mRelativeWordEndIndex; - private final int mRelativeSuggestedWordStartIndex; - private final int mRelativeSuggestedWordEndIndex; - - // Smart action. - private final int[] mActionIndices; + private TextClassifierEvent(Builder builder) { + mEventCategory = builder.mEventCategory; + mEventType = builder.mEventType; + mEntityTypes = builder.mEntityTypes; + mEventContext = builder.mEventContext; + mResultId = builder.mResultId; + mEventIndex = builder.mEventIndex; + mScores = builder.mScores; + mModelName = builder.mModelName; + mActionIndices = builder.mActionIndices; + mExtras = builder.mExtras == null ? Bundle.EMPTY : builder.mExtras; + } - // Language detection. - @Nullable private final String mLanguage; - private final float mScore; - - @Nullable private final String mModelName; - - private TextClassifierEvent( - int eventCategory, - int eventType, - String[] entityTypes, - TextClassificationContext eventContext, - String resultId, - int eventIndex, - long eventTime, - Bundle extras, - int relativeWordStartIndex, - int relativeWordEndIndex, - int relativeSuggestedWordStartIndex, - int relativeSuggestedWordEndIndex, - int[] actionIndex, - String language, - float score, - String modelVersion) { - mEventCategory = eventCategory; - mEventType = eventType; - mEntityTypes = entityTypes; - mEventContext = eventContext; - mResultId = resultId; - mEventIndex = eventIndex; - mEventTime = eventTime; - mExtras = extras; - mRelativeWordStartIndex = relativeWordStartIndex; - mRelativeWordEndIndex = relativeWordEndIndex; - mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; - mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; - mActionIndices = actionIndex; - mLanguage = language; - mScore = score; - mModelName = modelVersion; + private TextClassifierEvent(Parcel in) { + mEventCategory = in.readInt(); + mEventType = in.readInt(); + mEntityTypes = in.readStringArray(); + mEventContext = in.readParcelable(null); + mResultId = in.readString(); + mEventIndex = in.readInt(); + int scoresLength = in.readInt(); + mScores = new float[scoresLength]; + in.readFloatArray(mScores); + mModelName = in.readString(); + mActionIndices = in.createIntArray(); + mExtras = in.readBundle(); } @Override @@ -183,44 +181,62 @@ public final class TextClassifierEvent implements Parcelable { return 0; } + @NonNull + public static final Creator<TextClassifierEvent> CREATOR = new Creator<TextClassifierEvent>() { + @Override + public TextClassifierEvent createFromParcel(Parcel in) { + int token = in.readInt(); + if (token == PARCEL_TOKEN_TEXT_SELECTION_EVENT) { + return new TextSelectionEvent(in); + } + if (token == PARCEL_TOKEN_TEXT_LINKIFY_EVENT) { + return new TextLinkifyEvent(in); + } + if (token == PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT) { + return new LanguageDetectionEvent(in); + } + if (token == PARCEL_TOKEN_CONVERSATION_ACTION_EVENT) { + return new ConversationActionsEvent(in); + } + throw new IllegalStateException("Unexpected input event type token in parcel."); + } + + @Override + public TextClassifierEvent[] newArray(int size) { + return new TextClassifierEvent[size]; + } + }; + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(getParcelToken()); dest.writeInt(mEventCategory); dest.writeInt(mEventType); dest.writeStringArray(mEntityTypes); dest.writeParcelable(mEventContext, flags); dest.writeString(mResultId); dest.writeInt(mEventIndex); - dest.writeLong(mEventTime); - dest.writeBundle(mExtras); - dest.writeInt(mRelativeWordStartIndex); - dest.writeInt(mRelativeWordEndIndex); - dest.writeInt(mRelativeSuggestedWordStartIndex); - dest.writeInt(mRelativeSuggestedWordEndIndex); - dest.writeIntArray(mActionIndices); - dest.writeString(mLanguage); - dest.writeFloat(mScore); + dest.writeInt(mScores.length); + dest.writeFloatArray(mScores); dest.writeString(mModelName); + dest.writeIntArray(mActionIndices); + dest.writeBundle(mExtras); } - private static TextClassifierEvent readFromParcel(Parcel in) { - return new TextClassifierEvent( - /* eventCategory= */ in.readInt(), - /* eventType= */ in.readInt(), - /* entityTypes=*/ in.readStringArray(), - /* eventContext= */ in.readParcelable(null), - /* resultId= */ in.readString(), - /* eventIndex= */ in.readInt(), - /* eventTime= */ in.readLong(), - /* extras= */ in.readBundle(), - /* relativeWordStartIndex= */ in.readInt(), - /* relativeWordEndIndex= */ in.readInt(), - /* relativeSuggestedWordStartIndex= */ in.readInt(), - /* relativeSuggestedWordEndIndex= */ in.readInt(), - /* actionIndices= */ in.createIntArray(), - /* language= */ in.readString(), - /* score= */ in.readFloat(), - /* modelVersion= */ in.readString()); + private int getParcelToken() { + if (this instanceof TextSelectionEvent) { + return PARCEL_TOKEN_TEXT_SELECTION_EVENT; + } + if (this instanceof TextLinkifyEvent) { + return PARCEL_TOKEN_TEXT_LINKIFY_EVENT; + } + if (this instanceof LanguageDetectionEvent) { + return PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT; + } + if (this instanceof ConversationActionsEvent) { + return PARCEL_TOKEN_CONVERSATION_ACTION_EVENT; + } + throw new IllegalArgumentException("Unexpected type: " + this.getClass().getSimpleName()); } /** @@ -241,6 +257,8 @@ public final class TextClassifierEvent implements Parcelable { /** * Returns an array of entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}. + * + * @see Builder#setEntityTypes(String...) for supported types. */ @NonNull public String[] getEntityTypes() { @@ -270,52 +288,20 @@ public final class TextClassifierEvent implements Parcelable { return mEventIndex; } - // TODO: Remove this API. /** - * Returns the time this event occurred. This is the number of milliseconds since - * January 1, 1970, 00:00:00 GMT. 0 indicates not set. - */ - public long getEventTime() { - return mEventTime; - } - - /** - * Returns a bundle containing non-structured extra information about this event. - * - * <p><b>NOTE: </b>Do not modify this bundle. + * Returns the scores of the suggestions. */ @NonNull - public Bundle getExtras() { - return mExtras; - } - - /** - * For smart selection. Returns the relative word index of the start of the selection. - */ - public int getRelativeWordStartIndex() { - return mRelativeWordStartIndex; - } - - /** - * For smart selection. Returns the relative word (exclusive) index of the end of the selection. - */ - public int getRelativeWordEndIndex() { - return mRelativeWordEndIndex; - } - - /** - * For smart selection. Returns the relative word index of the start of the smart selection. - */ - public int getRelativeSuggestedWordStartIndex() { - return mRelativeSuggestedWordStartIndex; + public float[] getScores() { + return mScores; } /** - * For smart selection. Returns the relative word (exclusive) index of the end of the - * smart selection. + * Returns the model name. */ - public int getRelativeSuggestedWordEndIndex() { - return mRelativeSuggestedWordEndIndex; + @Nullable + public String getModelName() { + return mModelName; } /** @@ -323,6 +309,8 @@ public final class TextClassifierEvent implements Parcelable { * Actions are usually returned by the text classifier in priority order with the most * preferred action at index 0. This list gives an indication of the position of the actions * that are being reported. + * + * @see Builder#setActionIndices(int...) */ @NonNull public int[] getActionIndices() { @@ -330,110 +318,158 @@ public final class TextClassifierEvent implements Parcelable { } /** - * For language detection. Returns the language tag for the detected locale. - * @see java.util.Locale#forLanguageTag(String). - */ - @Nullable - public String getLanguage() { - return mLanguage; - } - - /** - * Returns the score of the suggestion. + * Returns a bundle containing non-structured extra information about this event. + * + * <p><b>NOTE: </b>Do not modify this bundle. */ - public float getScore() { - return mScore; + @NonNull + public Bundle getExtras() { + return mExtras; } - /** - * Returns the model name. - * @hide - */ - @Nullable - public String getModelName() { - return mModelName; + @Override + public String toString() { + StringBuilder out = new StringBuilder(128); + out.append(this.getClass().getSimpleName()); + out.append("{"); + out.append("mEventCategory=").append(mEventCategory); + out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes)); + out.append(", mEventContext=").append(mEventContext); + out.append(", mResultId=").append(mResultId); + out.append(", mEventIndex=").append(mEventIndex); + out.append(", mExtras=").append(mExtras); + out.append(", mScores=").append(Arrays.toString(mScores)); + out.append(", mModelName=").append(mModelName); + out.append(", mActionIndices=").append(Arrays.toString(mActionIndices)); + out.append("}"); + return out.toString(); } /** * Builder to build a text classifier event. + * + * @param <T> The subclass to be built. */ - public static final class Builder { + public abstract static class Builder<T extends Builder<T>> { private final int mEventCategory; private final int mEventType; private String[] mEntityTypes = new String[0]; - @Nullable private TextClassificationContext mEventContext; - @Nullable private String mResultId; + @Nullable + private TextClassificationContext mEventContext; + @Nullable + private String mResultId; private int mEventIndex; - private long mEventTime; - @Nullable private Bundle mExtras; - private int mRelativeWordStartIndex; - private int mRelativeWordEndIndex; - private int mRelativeSuggestedWordStartIndex; - private int mRelativeSuggestedWordEndIndex; - private int[] mActionIndices = new int[0]; - @Nullable private String mLanguage; - private float mScore; - + private float[] mScores = new float[0]; + @Nullable private String mModelName; + private int[] mActionIndices = new int[0]; + @Nullable + private Bundle mExtras; /** * Creates a builder for building {@link TextClassifierEvent}s. * * @param eventCategory The event category. e.g. {@link #CATEGORY_SELECTION} - * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED} + * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED} */ - public Builder(@Category int eventCategory, @Type int eventType) { + private Builder(@Category int eventCategory, @Type int eventType) { mEventCategory = eventCategory; mEventType = eventType; } /** * Sets the entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}. + * <p> + * Supported types: + * <p>See {@link TextClassifier.EntityType} + * <p>See {@link ConversationAction.ActionType} + * <p>See {@link ULocale#toLanguageTag()} */ @NonNull - public Builder setEntityTypes(@NonNull String... entityTypes) { + public T setEntityTypes(@NonNull String... entityTypes) { + Preconditions.checkNotNull(entityTypes); mEntityTypes = new String[entityTypes.length]; System.arraycopy(entityTypes, 0, mEntityTypes, 0, entityTypes.length); - return this; + return self(); } /** * Sets the event context. */ @NonNull - public Builder setEventContext(@Nullable TextClassificationContext eventContext) { + public T setEventContext(@Nullable TextClassificationContext eventContext) { mEventContext = eventContext; - return this; + return self(); } /** * Sets the id of the text classifier result related to this event. */ @NonNull - public Builder setResultId(@Nullable String resultId) { + public T setResultId(@Nullable String resultId) { mResultId = resultId; - return this; + return self(); } /** - * Sets the index of this events in the series of events it belongs to. + * Sets the index of this event in the series of events it belongs to. */ @NonNull - public Builder setEventIndex(int eventIndex) { + public T setEventIndex(int eventIndex) { mEventIndex = eventIndex; - return this; + return self(); + } + + /** + * Sets the scores of the suggestions. + */ + @NonNull + public T setScores(@NonNull float... scores) { + Preconditions.checkNotNull(scores); + mScores = new float[scores.length]; + System.arraycopy(scores, 0, mScores, 0, scores.length); + return self(); } - // TODO: Remove this API. /** - * Sets the time this event occurred. This is the number of milliseconds since - * January 1, 1970, 00:00:00 GMT. 0 indicates not set. + * Sets the model name string. */ @NonNull - public Builder setEventTime(long eventTime) { - mEventTime = eventTime; - return this; + public T setModelName(@Nullable String modelVersion) { + mModelName = modelVersion; + return self(); + } + + /** + * Sets the indices of the actions involved in this event. Actions are usually returned by + * the text classifier in priority order with the most preferred action at index 0. + * These indices give an indication of the position of the actions that are being reported. + * <p> + * E.g. + * <pre> + * // 3 smart actions are shown at index 0, 1, 2 respectively in response to a link click. + * new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_ACTIONS_SHOWN) + * .setEventIndex(0, 1, 2) + * ... + * .build(); + * + * ... + * + * // Smart action at index 1 is activated. + * new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_SMART_ACTION) + * .setEventIndex(1) + * ... + * .build(); + * </pre> + * + * @see TextClassification#getActions() + */ + @NonNull + public T setActionIndices(@NonNull int... actionIndices) { + mActionIndices = new int[actionIndices.length]; + System.arraycopy(actionIndices, 0, mActionIndices, 0, actionIndices.length); + return self(); } /** @@ -445,136 +481,545 @@ public final class TextClassifierEvent implements Parcelable { * objects in this bundle. */ @NonNull - public Builder setExtras(@NonNull Bundle extras) { + public T setExtras(@NonNull Bundle extras) { mExtras = Preconditions.checkNotNull(extras); - return this; + return self(); + } + + abstract T self(); + } + + /** + * This class represents events that are related to the smart text selection feature. + * <p> + * <pre> + * // User started a selection. e.g. "York" in text "New York City, NY". + * new TextSelectionEvent.Builder(TYPE_SELECTION_STARTED) + * .setEventContext(classificationContext) + * .setEventIndex(0) + * .build(); + * + * // System smart-selects a recognized entity. e.g. "New York City". + * new TextSelectionEvent.Builder(TYPE_SMART_SELECTION_MULTI) + * .setEventContext(classificationContext) + * .setResultId(textSelection.getId()) + * .setRelativeWordStartIndex(-1) // Goes back one word to "New" from "York". + * .setRelativeWordEndIndex(2) // Goes forward 2 words from "York" to start of ",". + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(1) + * .build(); + * + * // User resets the selection to the original selection. i.e. "York". + * new TextSelectionEvent.Builder(TYPE_SELECTION_RESET) + * .setEventContext(classificationContext) + * .setResultId(textSelection.getId()) + * .setRelativeSuggestedWordStartIndex(-1) // Repeated from above. + * .setRelativeSuggestedWordEndIndex(2) // Repeated from above. + * .setRelativeWordStartIndex(0) // Original selection is always at (0, 1]. + * .setRelativeWordEndIndex(1) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(2) + * .build(); + * + * // User modified the selection. e.g. "New". + * new TextSelectionEvent.Builder(TYPE_SELECTION_MODIFIED) + * .setEventContext(classificationContext) + * .setResultId(textSelection.getId()) + * .setRelativeSuggestedWordStartIndex(-1) // Repeated from above. + * .setRelativeSuggestedWordEndIndex(2) // Repeated from above. + * .setRelativeWordStartIndex(-1) // Goes backward one word from "York" to + * "New". + * .setRelativeWordEndIndex(0) // Goes backward one word to exclude "York". + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(3) + * .build(); + * + * // Smart (contextual) actions (at indices, 0, 1, 2) presented to the user. + * // e.g. "Map", "Ride share", "Explore". + * new TextSelectionEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(0, 1, 2) + * .setEventIndex(4) + * .build(); + * + * // User chooses the "Copy" action. + * new TextSelectionEvent.Builder(TYPE_COPY_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(5) + * .build(); + * + * // User chooses smart action at index 1. i.e. "Ride share". + * new TextSelectionEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(1) + * .setEventIndex(5) + * .build(); + * + * // Selection dismissed. + * new TextSelectionEvent.Builder(TYPE_SELECTION_DESTROYED) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(6) + * .build(); + * </pre> + * <p> + */ + public static final class TextSelectionEvent extends TextClassifierEvent implements Parcelable { + + @NonNull + public static final Creator<TextSelectionEvent> CREATOR = + new Creator<TextSelectionEvent>() { + @Override + public TextSelectionEvent createFromParcel(Parcel in) { + in.readInt(); // skip token, we already know this is a TextSelectionEvent + return new TextSelectionEvent(in); + } + + @Override + public TextSelectionEvent[] newArray(int size) { + return new TextSelectionEvent[size]; + } + }; + + final int mRelativeWordStartIndex; + final int mRelativeWordEndIndex; + final int mRelativeSuggestedWordStartIndex; + final int mRelativeSuggestedWordEndIndex; + + private TextSelectionEvent(TextSelectionEvent.Builder builder) { + super(builder); + mRelativeWordStartIndex = builder.mRelativeWordStartIndex; + mRelativeWordEndIndex = builder.mRelativeWordEndIndex; + mRelativeSuggestedWordStartIndex = builder.mRelativeSuggestedWordStartIndex; + mRelativeSuggestedWordEndIndex = builder.mRelativeSuggestedWordEndIndex; + } + + private TextSelectionEvent(Parcel in) { + super(in); + mRelativeWordStartIndex = in.readInt(); + mRelativeWordEndIndex = in.readInt(); + mRelativeSuggestedWordStartIndex = in.readInt(); + mRelativeSuggestedWordEndIndex = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(mRelativeWordStartIndex); + dest.writeInt(mRelativeWordEndIndex); + dest.writeInt(mRelativeSuggestedWordStartIndex); + dest.writeInt(mRelativeSuggestedWordEndIndex); } /** - * For smart selection. Sets the relative word index of the start of the selection. + * Returns the relative word index of the start of the selection. */ - @NonNull - public Builder setRelativeWordStartIndex(int relativeWordStartIndex) { - mRelativeWordStartIndex = relativeWordStartIndex; - return this; + public int getRelativeWordStartIndex() { + return mRelativeWordStartIndex; } /** - * For smart selection. Sets the relative word (exclusive) index of the end of the - * selection. + * Returns the relative word (exclusive) index of the end of the selection. */ - @NonNull - public Builder setRelativeWordEndIndex(int relativeWordEndIndex) { - mRelativeWordEndIndex = relativeWordEndIndex; - return this; + public int getRelativeWordEndIndex() { + return mRelativeWordEndIndex; } /** - * For smart selection. Sets the relative word index of the start of the smart selection. + * Returns the relative word index of the start of the smart selection. */ - @NonNull - public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) { - mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; - return this; + public int getRelativeSuggestedWordStartIndex() { + return mRelativeSuggestedWordStartIndex; } /** - * For smart selection. Sets the relative word (exclusive) index of the end of the + * Returns the relative word (exclusive) index of the end of the * smart selection. */ - @NonNull - public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) { - mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; - return this; + public int getRelativeSuggestedWordEndIndex() { + return mRelativeSuggestedWordEndIndex; } /** - * Sets the indices of the actions involved in this event. Actions are usually returned by - * the text classifier in priority order with the most preferred action at index 0. - * This index gives an indication of the position of the action that is being reported. + * Builder class for {@link TextSelectionEvent}. */ + public static final class Builder extends + TextClassifierEvent.Builder<TextSelectionEvent.Builder> { + int mRelativeWordStartIndex; + int mRelativeWordEndIndex; + int mRelativeSuggestedWordStartIndex; + int mRelativeSuggestedWordEndIndex; + + /** + * Creates a builder for building {@link TextSelectionEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED} + */ + public Builder(@Type int eventType) { + super(CATEGORY_SELECTION, eventType); + } + + /** + * Sets the relative word index of the start of the selection. + */ + @NonNull + public Builder setRelativeWordStartIndex(int relativeWordStartIndex) { + mRelativeWordStartIndex = relativeWordStartIndex; + return this; + } + + /** + * Sets the relative word (exclusive) index of the end of the + * selection. + */ + @NonNull + public Builder setRelativeWordEndIndex(int relativeWordEndIndex) { + mRelativeWordEndIndex = relativeWordEndIndex; + return this; + } + + /** + * Sets the relative word index of the start of the smart + * selection. + */ + @NonNull + public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) { + mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex; + return this; + } + + /** + * Sets the relative word (exclusive) index of the end of the + * smart selection. + */ + @NonNull + public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) { + mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex; + return this; + } + + @Override + TextSelectionEvent.Builder self() { + return this; + } + + /** + * Builds and returns a {@link TextSelectionEvent}. + */ + @NonNull + public TextSelectionEvent build() { + return new TextSelectionEvent(this); + } + } + } + + /** + * This class represents events that are related to the smart linkify feature. + * <p> + * <pre> + * // User clicked on a link. + * new TextLinkifyEvent.Builder(TYPE_LINK_CLICKED) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setEventIndex(0) + * .build(); + * + * // Smart (contextual) actions presented to the user in response to a link click. + * new TextLinkifyEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(range(textClassification.getActions().size())) + * .setEventIndex(1) + * .build(); + * + * // User chooses smart action at index 0. + * new TextLinkifyEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(textClassification.getEntity(0)) + * .setScore(textClassification.getConfidenceScore(entityType)) + * .setActionIndices(0) + * .setEventIndex(2) + * .build(); + * </pre> + */ + public static final class TextLinkifyEvent extends TextClassifierEvent implements Parcelable { + @NonNull - public Builder setActionIndices(@NonNull int... actionIndices) { - mActionIndices = new int[actionIndices.length]; - System.arraycopy(actionIndices, 0, mActionIndices, 0, actionIndices.length); - return this; + public static final Creator<TextLinkifyEvent> CREATOR = + new Creator<TextLinkifyEvent>() { + @Override + public TextLinkifyEvent createFromParcel(Parcel in) { + in.readInt(); // skip token, we already know this is a TextLinkifyEvent + return new TextLinkifyEvent(in); + } + + @Override + public TextLinkifyEvent[] newArray(int size) { + return new TextLinkifyEvent[size]; + } + }; + + private TextLinkifyEvent(Parcel in) { + super(in); + } + + private TextLinkifyEvent(TextLinkifyEvent.Builder builder) { + super(builder); } /** - * For language detection. Sets the language tag for the detected locale. - * @see java.util.Locale#forLanguageTag(String). + * Builder class for {@link TextLinkifyEvent}. */ + public static final class Builder + extends TextClassifierEvent.Builder<TextLinkifyEvent.Builder> { + /** + * Creates a builder for building {@link TextLinkifyEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION} + */ + public Builder(@Type int eventType) { + super(TextClassifierEvent.CATEGORY_LINKIFY, eventType); + } + + @Override + Builder self() { + return this; + } + + /** + * Builds and returns a {@link TextLinkifyEvent}. + */ + @NonNull + public TextLinkifyEvent build() { + return new TextLinkifyEvent(this); + } + } + } + + /** + * This class represents events that are related to the language detection feature. + * <p> + * <pre> + * // Translate action shown for foreign text. + * new LanguageDetectionEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(language) + * .setScore(score) + * .setActionIndices(textClassification.getActions().indexOf(translateAction)) + * .setEventIndex(0) + * .build(); + * + * // Translate action selected. + * new LanguageDetectionEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(textClassification.getId()) + * .setEntityTypes(language) + * .setScore(score) + * .setActionIndices(textClassification.getActions().indexOf(translateAction)) + * .setEventIndex(1) + * .build(); + */ + public static final class LanguageDetectionEvent extends TextClassifierEvent + implements Parcelable { + @NonNull - public Builder setLanguage(@Nullable String language) { - mLanguage = language; - return this; + public static final Creator<LanguageDetectionEvent> CREATOR = + new Creator<LanguageDetectionEvent>() { + @Override + public LanguageDetectionEvent createFromParcel(Parcel in) { + // skip token, we already know this is a LanguageDetectionEvent. + in.readInt(); + return new LanguageDetectionEvent(in); + } + + @Override + public LanguageDetectionEvent[] newArray(int size) { + return new LanguageDetectionEvent[size]; + } + }; + + @Nullable + private final ULocale mLocale; + + private LanguageDetectionEvent(Parcel in) { + super(in); + final String languageTag = in.readString(); + mLocale = languageTag == null ? null : ULocale.forLanguageTag(languageTag); + } + + private LanguageDetectionEvent(LanguageDetectionEvent.Builder builder) { + super(builder); + mLocale = builder.mLocale; } /** - * Sets the score of the suggestion. + * Returns the detected locale. */ - @NonNull - public Builder setScore(float score) { - mScore = score; - return this; + @Nullable + public ULocale getLocale() { + return mLocale; } /** - * Sets the model name string. - * @hide + * Builder class for {@link LanguageDetectionEvent}. */ - public Builder setModelName(@Nullable String modelVersion) { - mModelName = modelVersion; - return this; + public static final class Builder + extends TextClassifierEvent.Builder<LanguageDetectionEvent.Builder> { + @Nullable + private ULocale mLocale; + + /** + * Creates a builder for building {@link TextSelectionEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION} + */ + public Builder(@Type int eventType) { + super(TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType); + } + + /** + * Sets the detected locale. + */ + @NonNull + public Builder setLocale(@Nullable ULocale locale) { + mLocale = locale; + return this; + } + + @Override + Builder self() { + return this; + } + + /** + * Builds and returns a {@link LanguageDetectionEvent}. + */ + @NonNull + public LanguageDetectionEvent build() { + return new LanguageDetectionEvent(this); + } + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(mLocale == null ? null : mLocale.toLanguageTag()); + } + } + + /** + * This class represents events that are related to the conversation actions feature. + * <p> + * <pre> + * // Conversation (contextual) actions/replies generated. + * new ConversationActionsEvent.Builder(TYPE_ACTIONS_GENERATED) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEntityTypes(getTypes(conversationActions)) + * .setActionIndices(range(conversationActions.getActions().size())) + * .setEventIndex(0) + * .build(); + * + * // Conversation actions/replies presented to user. + * new ConversationActionsEvent.Builder(TYPE_ACTIONS_SHOWN) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEntityTypes(getTypes(conversationActions)) + * .setActionIndices(range(conversationActions.getActions().size())) + * .setEventIndex(1) + * .build(); + * + * // User clicked the "Reply" button to compose their custom reply. + * new ConversationActionsEvent.Builder(TYPE_MANUAL_REPLY) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEventIndex(2) + * .build(); + * + * // User selected a smart (contextual) action/reply. + * new ConversationActionsEvent.Builder(TYPE_SMART_ACTION) + * .setEventContext(classificationContext) + * .setResultId(conversationActions.getId()) + * .setEntityTypes(conversationActions.get(1).getType()) + * .setScore(conversationAction.get(1).getConfidenceScore()) + * .setActionIndices(1) + * .setEventIndex(2) + * .build(); + * </pre> + */ + public static final class ConversationActionsEvent extends TextClassifierEvent + implements Parcelable { + + @NonNull + public static final Creator<ConversationActionsEvent> CREATOR = + new Creator<ConversationActionsEvent>() { + @Override + public ConversationActionsEvent createFromParcel(Parcel in) { + // skip token, we already know this is a ConversationActionsEvent. + in.readInt(); + return new ConversationActionsEvent(in); + } + + @Override + public ConversationActionsEvent[] newArray(int size) { + return new ConversationActionsEvent[size]; + } + }; + + private ConversationActionsEvent(Parcel in) { + super(in); + } + + private ConversationActionsEvent(ConversationActionsEvent.Builder builder) { + super(builder); } /** - * Builds and returns a text classifier event. + * Builder class for {@link ConversationActionsEvent}. */ - @NonNull - public TextClassifierEvent build() { - mExtras = mExtras == null ? Bundle.EMPTY : mExtras; - return new TextClassifierEvent( - mEventCategory, - mEventType, - mEntityTypes, - mEventContext, - mResultId, - mEventIndex, - mEventTime, - mExtras, - mRelativeWordStartIndex, - mRelativeWordEndIndex, - mRelativeSuggestedWordStartIndex, - mRelativeSuggestedWordEndIndex, - mActionIndices, - mLanguage, - mScore, - mModelName); - } - // TODO: Add build(boolean validate). - } + public static final class Builder + extends TextClassifierEvent.Builder<ConversationActionsEvent.Builder> { + /** + * Creates a builder for building {@link TextSelectionEvent}s. + * + * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION} + */ + public Builder(@Type int eventType) { + super(TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType); + } - @Override - public String toString() { - StringBuilder out = new StringBuilder(128); - out.append("TextClassifierEvent{"); - out.append("mEventCategory=").append(mEventCategory); - out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes)); - out.append(", mEventContext=").append(mEventContext); - out.append(", mResultId=").append(mResultId); - out.append(", mEventIndex=").append(mEventIndex); - out.append(", mEventTime=").append(mEventTime); - out.append(", mExtras=").append(mExtras); - out.append(", mRelativeWordStartIndex=").append(mRelativeWordStartIndex); - out.append(", mRelativeWordEndIndex=").append(mRelativeWordEndIndex); - out.append(", mRelativeSuggestedWordStartIndex=").append(mRelativeSuggestedWordStartIndex); - out.append(", mRelativeSuggestedWordEndIndex=").append(mRelativeSuggestedWordEndIndex); - out.append(", mActionIndices=").append(Arrays.toString(mActionIndices)); - out.append(", mLanguage=").append(mLanguage); - out.append(", mScore=").append(mScore); - out.append(", mModelName=").append(mModelName); - out.append("}"); - return out.toString(); + @Override + Builder self() { + return this; + } + + /** + * Builds and returns a {@link ConversationActionsEvent}. + */ + @NonNull + public ConversationActionsEvent build() { + return new ConversationActionsEvent(this); + } + } } } diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java index 6a122506d0ac..3e088b8565f2 100644 --- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java +++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java @@ -65,9 +65,10 @@ public final class TextClassifierEventTronLogger { final LogMaker log = new LogMaker(category) .setSubtype(getLogType(event)) .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId()) - .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event)) - .addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScore()); - + .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event)); + if (event.getScores().length >= 1) { + log.addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScores()[0]); + } String[] entityTypes = event.getEntityTypes(); // The old logger does not support a field of list type, and thus workaround by store them // in three separate fields. This is not an issue with the new logger. diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 323bf597ab55..3297523b0da9 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -307,6 +307,8 @@ public final class TextClassifierImpl implements TextClassifier { final String detectLanguageTags = detectLanguageTagsFromText(request.getText()); final AnnotatorModel annotatorImpl = getAnnotatorImpl(request.getDefaultLocales()); + final boolean isSerializedEntityDataEnabled = + ExtrasUtils.isSerializedEntityDataEnabled(request); final AnnotatorModel.AnnotatedSpan[] annotations = annotatorImpl.annotate( textString, @@ -314,7 +316,10 @@ public final class TextClassifierImpl implements TextClassifier { refTime.toInstant().toEpochMilli(), refTime.getZone().getId(), localesString, - detectLanguageTags)); + detectLanguageTags, + entitiesToIdentify, + AnnotatorModel.AnnotationUsecase.SMART.getValue(), + isSerializedEntityDataEnabled)); for (AnnotatorModel.AnnotatedSpan span : annotations) { final AnnotatorModel.ClassificationResult[] results = span.getClassification(); @@ -326,7 +331,11 @@ public final class TextClassifierImpl implements TextClassifier { for (int i = 0; i < results.length; i++) { entityScores.put(results[i].getCollection(), results[i].getScore()); } - builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores); + Bundle extras = new Bundle(); + if (isSerializedEntityDataEnabled) { + ExtrasUtils.putEntities(extras, results); + } + builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores, extras); } final TextLinks links = builder.build(); final long endTimeMs = System.currentTimeMillis(); @@ -451,10 +460,6 @@ public final class TextClassifierImpl implements TextClassifier { Collection<String> expectedTypes = resolveActionTypesFromRequest(request); List<ConversationAction> conversationActions = new ArrayList<>(); for (ActionsSuggestionsModel.ActionSuggestion nativeSuggestion : nativeSuggestions) { - if (request.getMaxSuggestions() >= 0 - && conversationActions.size() == request.getMaxSuggestions()) { - break; - } String actionType = nativeSuggestion.getActionType(); if (!expectedTypes.contains(actionType)) { continue; @@ -484,6 +489,10 @@ public final class TextClassifierImpl implements TextClassifier { } conversationActions = ActionsSuggestionsHelper.removeActionsWithDuplicates(conversationActions); + if (request.getMaxSuggestions() >= 0 + && conversationActions.size() > request.getMaxSuggestions()) { + conversationActions = conversationActions.subList(0, request.getMaxSuggestions()); + } String resultId = ActionsSuggestionsHelper.createResultId( mContext, request.getConversation(), diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java index 66a72f9b2e9e..f3e0dc1ed843 100644 --- a/core/java/android/view/textclassifier/TextLinks.java +++ b/core/java/android/view/textclassifier/TextLinks.java @@ -281,6 +281,7 @@ public final class TextLinks implements Parcelable { /** * Returns a bundle containing custom data related to this TextLink. */ + @NonNull public Bundle getExtras() { return 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/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 564cfdd20d76..51ca80524090 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -933,12 +933,11 @@ public final class SelectionActionModeHelper { final String language = ExtrasUtils.getEntityType(foreignLanguageExtra); final float score = ExtrasUtils.getScore(foreignLanguageExtra); final String model = ExtrasUtils.getModelName(foreignLanguageExtra); - return new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType) + return new TextClassifierEvent.LanguageDetectionEvent.Builder(eventType) .setEventContext(classificationContext) .setResultId(classification.getId()) .setEntityTypes(language) - .setScore(score) + .setScores(score) .setActionIndices(classification.getActions().indexOf(translateAction)) .setModelName(model) .build(); 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 b51f8080569f..54338bf6a176 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; @@ -101,9 +103,7 @@ import android.view.animation.DecelerateInterpolator; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.Space; import android.widget.TextView; import android.widget.Toast; @@ -133,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 @@ -143,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. @@ -435,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; @@ -469,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); @@ -874,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(); } @@ -1207,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; @@ -1250,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(); @@ -1311,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) { @@ -1334,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; } @@ -1347,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) { @@ -1429,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)); } /** @@ -1520,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; + } } /** @@ -1598,13 +1648,14 @@ 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; private final Intent mFillInIntent; private final int mFillInFlags; private final float mModifiedScore; - private boolean mIsSuspended; + private boolean mIsSuspended = false; SelectableTargetInfo(DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget, float modifiedScore) { @@ -1619,6 +1670,8 @@ public class ChooserActivity extends ResolverActivity { final PackageManager pm = getPackageManager(); mBadgeIcon = pm.getApplicationIcon(ai.applicationInfo); mBadgeContentDescription = pm.getApplicationLabel(ai.applicationInfo); + mIsSuspended = + (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0; } } } @@ -1633,8 +1686,8 @@ public class ChooserActivity extends ResolverActivity { mFillInIntent = null; mFillInFlags = 0; - ApplicationInfo ai = sourceInfo.getResolveInfo().activityInfo.applicationInfo; - mIsSuspended = (ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0; + + mDisplayLabel = sanitizeDisplayLabel(chooserTarget.getTitle()); } private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) { @@ -1647,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() { @@ -1785,7 +1846,7 @@ public class ChooserActivity extends ResolverActivity { @Override public CharSequence getDisplayLabel() { - return mChooserTarget.getTitle(); + return mDisplayLabel; } @Override @@ -1836,7 +1897,7 @@ public class ChooserActivity extends ResolverActivity { return; } - if (mChooserRowAdapter.calculateMaxTargetsPerRow(right - left) + if (mChooserRowAdapter.calculateChooserTargetWidth(right - left) || mAdapterView.getAdapter() == null) { mAdapterView.setAdapter(mChooserRowAdapter); @@ -2018,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"); } @@ -2049,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); } @@ -2082,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; @@ -2198,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++) { @@ -2242,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; } @@ -2274,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) { @@ -2325,9 +2396,9 @@ public class ChooserActivity extends ResolverActivity { class ChooserRowAdapter extends BaseAdapter { private ChooserListAdapter mChooserListAdapter; private final LayoutInflater mLayoutInflater; - private int mCalculatedMaxTargetsPerRow = MAX_TARGETS_PER_ROW_LANDSCAPE; private DirectShareViewHolder mDirectShareViewHolder; + private int mChooserTargetWidth = 0; private static final int VIEW_TYPE_DIRECT_SHARE = 0; private static final int VIEW_TYPE_NORMAL = 1; @@ -2356,25 +2427,19 @@ public class ChooserActivity extends ResolverActivity { } /** - * Determine how many targets can comfortably fit in a single row. + * Calculate the chooser target width to maximize space per item * * @param width The new row width to use for recalculation - * @return true if the numbers of targets per row has changed + * @return true if the view width has changed */ - public boolean calculateMaxTargetsPerRow(int width) { - int targetWidth = getResources().getDimensionPixelSize( - R.dimen.chooser_target_width); - - if (targetWidth == 0 || width == 0) { + public boolean calculateChooserTargetWidth(int width) { + if (width == 0) { return false; } - int margin = getResources().getDimensionPixelSize( - R.dimen.chooser_edge_margin_normal); - - int newCount = (width - margin * 2) / targetWidth; - if (newCount != mCalculatedMaxTargetsPerRow) { - mCalculatedMaxTargetsPerRow = newCount; + int newWidth = width / getMaxTargetsPerRow(); + if (newWidth != mChooserTargetWidth) { + mChooserTargetWidth = newWidth; return true; } @@ -2388,7 +2453,7 @@ public class ChooserActivity extends ResolverActivity { maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE; } - return Math.min(maxTargets, mCalculatedMaxTargetsPerRow); + return maxTargets; } @Override @@ -2498,6 +2563,8 @@ public class ChooserActivity extends ResolverActivity { private RowViewHolder loadViewsIntoRow(RowViewHolder holder) { final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final int exactSpec = MeasureSpec.makeMeasureSpec(mChooserTargetWidth, + MeasureSpec.EXACTLY); int columnCount = holder.getColumnCount(); final boolean isDirectShare = holder instanceof DirectShareViewHolder; @@ -2533,20 +2600,20 @@ public class ChooserActivity extends ResolverActivity { } // Force height to be a given so we don't have visual disruption during scaling. - v.measure(spec, spec); - setViewHeight(v, v.getMeasuredHeight()); + v.measure(exactSpec, spec); + setViewBounds(v, v.getMeasuredWidth(), v.getMeasuredHeight()); } final ViewGroup viewGroup = holder.getViewGroup(); // Pre-measure and fix height so we can scale later. holder.measure(); - setViewHeight(viewGroup, holder.getMeasuredRowHeight()); + setViewBounds(viewGroup, LayoutParams.MATCH_PARENT, holder.getMeasuredRowHeight()); if (isDirectShare) { DirectShareViewHolder dsvh = (DirectShareViewHolder) holder; - setViewHeight(dsvh.getRow(0), dsvh.getMinRowHeight()); - setViewHeight(dsvh.getRow(1), dsvh.getMinRowHeight()); + setViewBounds(dsvh.getRow(0), LayoutParams.MATCH_PARENT, dsvh.getMinRowHeight()); + setViewBounds(dsvh.getRow(1), LayoutParams.MATCH_PARENT, dsvh.getMinRowHeight()); } viewGroup.setTag(holder); @@ -2554,13 +2621,14 @@ public class ChooserActivity extends ResolverActivity { return holder; } - private void setViewHeight(View view, int heightPx) { + private void setViewBounds(View view, int widthPx, int heightPx) { LayoutParams lp = view.getLayoutParams(); if (lp == null) { - lp = new LayoutParams(LayoutParams.MATCH_PARENT, heightPx); + lp = new LayoutParams(widthPx, heightPx); view.setLayoutParams(lp); } else { lp.height = heightPx; + lp.width = widthPx; } } @@ -2590,12 +2658,24 @@ public class ChooserActivity extends ResolverActivity { } } + /** + * Need to merge CALLER + ranked STANDARD into a single row. All other types + * are placed into their own row as determined by their target type, and dividers + * are added in the list to separate each type. + */ + int getRowType(int rowPosition) { + int positionType = mChooserListAdapter.getPositionTargetType(rowPosition); + if (positionType == ChooserListAdapter.TARGET_CALLER) { + return ChooserListAdapter.TARGET_STANDARD; + } + + return positionType; + } + void bindViewHolder(int rowPosition, RowViewHolder holder) { final int start = getFirstRowPosition(rowPosition); - final int startType = mChooserListAdapter.getPositionTargetType(start); - - final int lastStartType = mChooserListAdapter.getPositionTargetType( - getFirstRowPosition(rowPosition - 1)); + final int startType = getRowType(start); + final int lastStartType = getRowType(getFirstRowPosition(rowPosition - 1)); final ViewGroup row = holder.getViewGroup(); @@ -2607,7 +2687,7 @@ public class ChooserActivity extends ResolverActivity { int columnCount = holder.getColumnCount(); int end = start + columnCount - 1; - while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) { + while (getRowType(end) != startType && end >= start) { end--; } @@ -2659,14 +2739,15 @@ public class ChooserActivity extends ResolverActivity { return row * getMaxTargetsPerRow(); } - final int callerCount = mChooserListAdapter.getCallerTargetCount(); - final int callerRows = (int) Math.ceil((float) callerCount / getMaxTargetsPerRow()); - if (row < callerRows + serviceRows) { + final int callerAndRankedCount = mChooserListAdapter.getCallerTargetCount() + + mChooserListAdapter.getRankedTargetCount(); + final int callerAndRankedRows = getCallerAndRankedTargetRowCount(); + if (row < callerAndRankedRows + serviceRows) { return serviceCount + (row - serviceRows) * getMaxTargetsPerRow(); } - return callerCount + serviceCount - + (row - callerRows - serviceRows) * getMaxTargetsPerRow(); + return callerAndRankedCount + serviceCount + + (row - callerAndRankedRows - serviceRows) * getMaxTargetsPerRow(); } public void handleScroll(View v, int y, int oldy) { @@ -2712,11 +2793,6 @@ public class ChooserActivity extends ResolverActivity { return mMeasuredRowHeight; } - protected void addSpacer(ViewGroup row) { - row.addView(new Space(ChooserActivity.this), - new LinearLayout.LayoutParams(0, 0, 1)); - } - public void setItemIndex(int itemIndex, int listIndex) { mItemIndices[itemIndex] = listIndex; } @@ -2756,10 +2832,6 @@ public class ChooserActivity extends ResolverActivity { mRow.addView(v); mCells[index] = v; - if (index != (mCells.length - 1)) { - addSpacer(mRow); - } - return mRow; } @@ -2794,10 +2866,6 @@ public class ChooserActivity extends ResolverActivity { row.addView(v); mCells[index] = v; - if (index % mCellCountPerRow != (mCellCountPerRow - 1)) { - addSpacer(row); - } - return row; } 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/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java index 1aef573f5189..b0855f494ffd 100644 --- a/core/java/com/android/internal/os/RoSystemProperties.java +++ b/core/java/com/android/internal/os/RoSystemProperties.java @@ -60,7 +60,7 @@ public class RoSystemProperties { public static final boolean FW_SYSTEM_USER_SPLIT = SystemProperties.getBoolean("ro.fw.system_user_split", false); public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER = - SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", true); + SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", false); // ------ ro.crypto.* -------- // public static final CryptoProperties.state_values CRYPTO_STATE = 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/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index d945e139dd0f..32fce8f78330 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -630,7 +630,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom; } - Drawable bg = getBackground(); + Drawable bg = super.getBackground(); if (bg != null) { bg.setBounds(drawingBounds); } @@ -1238,6 +1238,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable; } + @Override + public Drawable getBackground() { + return mOriginalBackgroundDrawable; + } + private int calculateStatusBarColor() { return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_STATUS, mSemiTransparentBarColor, mWindow.mStatusBarColor, diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 16d6c52d82ea..21f8d87e7e8c 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -45,6 +45,7 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Color; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.session.MediaController; @@ -115,6 +116,7 @@ import com.android.internal.widget.SwipeDismissLayout; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.List; /** * Android-specific Window. @@ -2464,9 +2466,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } if (!targetPreQ) { mEnsureStatusBarContrastWhenTransparent = a.getBoolean( - R.styleable.Window_ensureStatusBarContrastWhenTransparent, false); + R.styleable.Window_ensuringStatusBarContrastWhenTransparent, false); mEnsureNavigationBarContrastWhenTransparent = a.getBoolean( - R.styleable.Window_ensureNavigationBarContrastWhenTransparent, true); + R.styleable.Window_ensuringNavigationBarContrastWhenTransparent, true); } WindowManager.LayoutParams params = getAttributes(); @@ -3857,7 +3859,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override - public void setEnsureStatusBarContrastWhenTransparent(boolean ensureContrast) { + public void setEnsuringStatusBarContrastWhenTransparent(boolean ensureContrast) { mEnsureStatusBarContrastWhenTransparent = ensureContrast; if (mDecor != null) { mDecor.updateColorViews(null, false /* animate */); @@ -3865,12 +3867,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override - public boolean isEnsureStatusBarContrastWhenTransparent() { + public boolean isEnsuringStatusBarContrastWhenTransparent() { return mEnsureStatusBarContrastWhenTransparent; } @Override - public void setEnsureNavigationBarContrastWhenTransparent(boolean ensureContrast) { + public void setEnsuringNavigationBarContrastWhenTransparent(boolean ensureContrast) { mEnsureNavigationBarContrastWhenTransparent = ensureContrast; if (mDecor != null) { mDecor.updateColorViews(null, false /* animate */); @@ -3878,7 +3880,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override - public boolean isEnsureNavigationBarContrastWhenTransparent() { + public boolean isEnsuringNavigationBarContrastWhenTransparent() { return mEnsureNavigationBarContrastWhenTransparent; } @@ -3926,4 +3928,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public WindowInsetsController getInsetsController() { return mDecor.getWindowInsetsController(); } + + @Override + public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { + getViewRootImpl().setRootSystemGestureExclusionRects(rects); + } + + @Override + @NonNull + public List<Rect> getSystemGestureExclusionRects() { + return getViewRootImpl().getRootSystemGestureExclusionRects(); + } } 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 967abce60cd3..f2665020b49e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -174,7 +174,6 @@ extern int register_android_database_CursorWindow(JNIEnv* env); extern int register_android_database_SQLiteConnection(JNIEnv* env); extern int register_android_database_SQLiteGlobal(JNIEnv* env); extern int register_android_database_SQLiteDebug(JNIEnv* env); -extern int register_android_nio_utils(JNIEnv* env); extern int register_android_os_Debug(JNIEnv* env); extern int register_android_os_GraphicsEnvironment(JNIEnv* env); extern int register_android_os_HidlSupport(JNIEnv* env); @@ -679,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; @@ -1025,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. @@ -1422,7 +1432,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_NativeHandle), REG_JNI(register_android_os_VintfObject), REG_JNI(register_android_os_VintfRuntimeInfo), - REG_JNI(register_android_nio_utils), REG_JNI(register_android_graphics_Canvas), // This needs to be before register_android_graphics_Graphics, or the latter // will not be able to find the jmethodID for ColorSpace.get(). diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 09f0e8e232bf..55abc932cff2 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -773,54 +773,18 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz, * ETC1 methods. */ -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - -/* Cache method IDs each time the class is loaded. */ - -static void -nativeClassInitBuffer(JNIEnv *env) -{ - jclass nioAccessClassLocal = FindClassOrDie(env, "java/nio/NIOAccess"); - nioAccessClass = MakeGlobalRefOrDie(env, nioAccessClassLocal); - getBasePointerID = GetStaticMethodIDOrDie(env, nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = GetStaticMethodIDOrDie(env, nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = GetStaticMethodIDOrDie(env, nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - jclass bufferClassLocal = FindClassOrDie(env, "java/nio/Buffer"); - bufferClass = MakeGlobalRefOrDie(env, bufferClassLocal); - positionID = GetFieldIDOrDie(env, bufferClass, "position", "I"); - limitID = GetFieldIDOrDie(env, bufferClass, "limit", "I"); - elementSizeShiftID = GetFieldIDOrDie(env, bufferClass, "_elementSizeShift", "I"); -} - static void * getPointer(JNIEnv *_env, jobject buffer, jint *remaining) { jint position; jint limit; jint elementSizeShift; - jlong pointer; - - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); + jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); if (pointer != 0L) { - return reinterpret_cast<void *>(pointer); + pointer += position << elementSizeShift; } - return NULL; + *remaining = (limit - position) << elementSizeShift; + return reinterpret_cast<void*>(pointer); } class BufferHelper { @@ -1101,7 +1065,6 @@ static const ClassRegistrationInfo gClasses[] = { int register_android_opengl_classes(JNIEnv* env) { - nativeClassInitBuffer(env); int result = 0; for (int i = 0; i < NELEM(gClasses); i++) { const ClassRegistrationInfo* cri = &gClasses[i]; diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp index 822b74a6b990..17a02b24c697 100644 --- a/core/jni/android_media_AudioProductStrategies.cpp +++ b/core/jni/android_media_AudioProductStrategies.cpp @@ -39,7 +39,7 @@ using namespace android; // ---------------------------------------------------------------------------- -static const char* const kClassPathName = "android/media/audiopolicy/AudioProductStrategies"; +static const char* const kClassPathName = "android/media/audiopolicy/AudioProductStrategy"; static const char* const kAudioProductStrategyClassPathName = "android/media/audiopolicy/AudioProductStrategy"; @@ -194,34 +194,12 @@ exit: return jStatus; } -static jint -android_media_AudioSystem_getProductStrategyFromAudioAttributes(JNIEnv *env, jobject clazz, - jobject jAudioAttributes) -{ - JNIAudioAttributeHelper::UniqueAaPtr attributes = JNIAudioAttributeHelper::makeUnique(); - jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, - jAudioAttributes, - attributes.get()); - if (jStatus != (jint)AUDIO_JAVA_SUCCESS) { - return jStatus; - } - product_strategy_t psId; - status_t status = AudioSystem::getProductStrategyFromAudioAttributes( - AudioAttributes(*attributes.get()), psId); - if (status != NO_ERROR) { - return nativeToJavaStatus(status); - } - return psId; -} - /* * JNI registration. */ static const JNINativeMethod gMethods[] = { {"native_list_audio_product_strategies", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioSystem_listAudioProductStrategies}, - {"native_get_product_strategies_from_audio_attributes", "(Landroid/media/AudioAttributes;)I", - (void *)android_media_AudioSystem_getProductStrategyFromAudioAttributes}, }; int register_android_media_AudioProductStrategies(JNIEnv *env) diff --git a/core/jni/android_media_AudioVolumeGroups.cpp b/core/jni/android_media_AudioVolumeGroups.cpp index 64f0c1e33e1c..7098451901c4 100644 --- a/core/jni/android_media_AudioVolumeGroups.cpp +++ b/core/jni/android_media_AudioVolumeGroups.cpp @@ -39,7 +39,7 @@ using namespace android; // ---------------------------------------------------------------------------- -static const char* const kClassPathName = "android/media/audiopolicy/AudioVolumeGroups"; +static const char* const kClassPathName = "android/media/audiopolicy/AudioVolumeGroup"; static const char* const kAudioVolumeGroupClassPathName = "android/media/audiopolicy/AudioVolumeGroup"; diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index dd754f35bba8..28c59db6b932 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -270,7 +270,7 @@ static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jint return jniCreateFileDescriptor(env, fd); } -static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) { +static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) { int fd = jniGetFDFromFileDescriptor(env, javaFd); int rcode; std::vector<uint8_t> buf(MAXPACKETSIZE, 0); @@ -291,7 +291,10 @@ static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, reinterpret_cast<jbyte*>(buf.data())); } - return answer; + jclass class_DnsResponse = env->FindClass("android/net/DnsResolver$DnsResponse"); + jmethodID ctor = env->GetMethodID(class_DnsResponse, "<init>", "([BI)V"); + + return env->NewObject(class_DnsResponse, ctor, answer, rcode); } static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) { @@ -354,7 +357,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket }, { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend }, { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery }, - { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult }, + { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult }, { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel }, }; diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp index ed8c6038f69d..1e6d49e49b72 100644 --- a/core/jni/android_nio_utils.cpp +++ b/core/jni/android_nio_utils.cpp @@ -18,78 +18,29 @@ #include "core_jni_helpers.h" -struct NioJNIData { - jclass nioAccessClass; - - jmethodID getBasePointerID; - jmethodID getBaseArrayID; - jmethodID getBaseArrayOffsetID; -}; - -static NioJNIData gNioJNI; - -void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { - assert(array); - - jlong pointer; - jint offset; - void *data; +namespace android { - pointer = _env->CallStaticLongMethod(gNioJNI.nioAccessClass, - gNioJNI.getBasePointerID, buffer); +AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) + : fEnv(env), fCommit(commit) { + jlong pointer = jniGetNioBufferPointer(fEnv, nioBuffer); if (pointer != 0L) { - *array = NULL; - return reinterpret_cast<void *>(pointer); + // Buffer is backed by a direct buffer. + fArray = nullptr; + fElements = nullptr; + fPointer = reinterpret_cast<void*>(pointer); + } else { + // Buffer is backed by a managed array. + jint byteOffset = jniGetNioBufferBaseArrayOffset(fEnv, nioBuffer); + fArray = jniGetNioBufferBaseArray(fEnv, nioBuffer); + fElements = fEnv->GetPrimitiveArrayCritical(fArray, /* isCopy= */ nullptr); + fPointer = reinterpret_cast<void*>(reinterpret_cast<char*>(fElements) + byteOffset); } - - *array = (jarray) _env->CallStaticObjectMethod(gNioJNI.nioAccessClass, - gNioJNI.getBaseArrayID, buffer); - offset = _env->CallStaticIntMethod(gNioJNI.nioAccessClass, - gNioJNI.getBaseArrayOffsetID, buffer); - data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - - return (void *) ((char *) data + offset); } - -void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, - jboolean commit) { - _env->ReleasePrimitiveArrayCritical(array, data, - commit ? 0 : JNI_ABORT); -} - -/////////////////////////////////////////////////////////////////////////////// - -android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, - jboolean commit) { - fEnv = env; - fCommit = commit; - fPointer = android::nio_getPointer(env, nioBuffer, &fArray); -} - -android::AutoBufferPointer::~AutoBufferPointer() { - if (NULL != fArray) { - android::nio_releasePointer(fEnv, fArray, fPointer, fCommit); +AutoBufferPointer::~AutoBufferPointer() { + if (nullptr != fArray) { + fEnv->ReleasePrimitiveArrayCritical(fArray, fElements, fCommit ? 0 : JNI_ABORT); } } -/////////////////////////////////////////////////////////////////////////////// - -namespace android { - -int register_android_nio_utils(JNIEnv* env) { - jclass localClass = FindClassOrDie(env, "java/nio/NIOAccess"); - gNioJNI.getBasePointerID = GetStaticMethodIDOrDie(env, localClass, "getBasePointer", - "(Ljava/nio/Buffer;)J"); - gNioJNI.getBaseArrayID = GetStaticMethodIDOrDie(env, localClass, "getBaseArray", - "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - gNioJNI.getBaseArrayOffsetID = GetStaticMethodIDOrDie(env, localClass, "getBaseArrayOffset", - "(Ljava/nio/Buffer;)I"); - - // now record a permanent version of the class ID - gNioJNI.nioAccessClass = MakeGlobalRefOrDie(env, localClass); - - return 0; -} - -} +} // namespace android diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h index c634cb917719..aa75dd0c7e32 100644 --- a/core/jni/android_nio_utils.h +++ b/core/jni/android_nio_utils.h @@ -20,52 +20,60 @@ #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. - * For performance, it does not create any global references, so the getPointer - * (and releasePointer if array is returned non-null) must be done in the - * same JNI stack-frame. - * - * @param env The current JNI env - * @param buffer The nio.Buffer object - * @param array REQUIRED. Output. If on return it is set to non-null, then - * nio_releasePointer must be called with the array - * and the returned pointer when the caller is through with it. - * If on return it is set to null, do not call - * nio_releasePointer. - * @return The pointer to the memory in the buffer object - */ -void* nio_getPointer(JNIEnv *env, jobject buffer, jarray *array); /** - * Call this if android_nio_getPointer returned non-null in its array parameter. - * Pass that array and the returned pointer when you are done accessing the - * pointer. If called (i.e. array is non-null), it must be called in the same - * JNI stack-frame as getPointer + * Class providing scoped access to the memory backing a java.nio.Buffer instance. + * + * Instances of this class should only be allocated on the stack as heap allocation is not + * supported. * - * @param env The current JNI env - * @param buffer The array returned from android_nio_getPointer (!= null) - * @param pointer The pointer returned by android_nio_getPointer - * @param commit JNI_FALSE if the pointer was just read, and JNI_TRUE if - * the pointer was written to. + * Instances of this class do not create any global references for performance reasons. */ -void nio_releasePointer(JNIEnv *env, jarray array, void *pointer, - jboolean commit); - -class AutoBufferPointer { +class AutoBufferPointer final { public: + /** Constructor for an AutoBufferPointer instance. + * + * @param env The current JNI env + * @param nioBuffer Instance of a java.nio.Buffer whose memory will be accessed. + * @param commit JNI_TRUE if the underlying memory will be updated and should be + * copied back to the managed heap. JNI_FALSE if the data will + * not be modified or the modifications may be discarded. + * + * The commit parameter is only applicable if the buffer is backed by a managed heap + * array and the runtime had to provide a copy of the data rather than the original data. + */ AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit); + + /** Destructor for an AutoBufferPointer instance. + * + * Releases critical managed heap array pointer if acquired. + */ ~AutoBufferPointer(); + /** + * Returns a pointer to the current position of the buffer provided to the constructor. This + * pointer is only valid whilst the AutoBufferPointer instance remains in scope. + */ void* pointer() const { return fPointer; } private: - JNIEnv* fEnv; - void* fPointer; - jarray fArray; - jboolean fCommit; + JNIEnv* const fEnv; + void* fPointer; // Pointer to current buffer position when constructed. + void* fElements; // Pointer to array element 0 (null if buffer is direct, may be + // within fArray or point to a copy of the array). + jarray fArray; // Pointer to array on managed heap. + const jboolean fCommit; // Flag to commit data to source (when fElements is a copy of fArray). + + // Unsupported constructors and operators. + AutoBufferPointer() = delete; + AutoBufferPointer(AutoBufferPointer&) = delete; + AutoBufferPointer& operator=(AutoBufferPointer&) = delete; + static void* operator new(std::size_t); + static void* operator new[](std::size_t); + static void* operator new(std::size_t, void*); + static void* operator new[](std::size_t, void*); + static void operator delete(void*, std::size_t); + static void operator delete[](void*, std::size_t); }; } /* namespace android */ diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp index 717b50579325..4aeed8765165 100644 --- a/core/jni/android_opengl_EGL15.cpp +++ b/core/jni/android_opengl_EGL15.cpp @@ -35,16 +35,6 @@ static jclass egldisplayClass; static jclass eglsurfaceClass; static jclass eglconfigClass; static jclass eglcontextClass; -static jclass bufferClass; -static jclass nioAccessClass; - -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; static jmethodID egldisplayGetHandleID; static jmethodID eglconfigGetHandleID; @@ -116,24 +106,6 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject); // EGL 1.5 init - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); - jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage"); eglimageClass = (jclass) _env->NewGlobalRef(eglimageClassLocal); jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync"); @@ -160,23 +132,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } static void diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp index a4ab5db8c8d7..3d9a3b6687b1 100644 --- a/core/jni/android_opengl_GLES10.cpp +++ b/core/jni/android_opengl_GLES10.cpp @@ -29,15 +29,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -72,28 +63,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -104,23 +76,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -242,16 +208,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp index a5dcbf765b60..6d7f41e5b3b2 100644 --- a/core/jni/android_opengl_GLES10Ext.cpp +++ b/core/jni/android_opengl_GLES10Ext.cpp @@ -29,15 +29,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -72,28 +63,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -104,23 +76,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -242,16 +208,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp index be86a037bfbd..39ef41a0e19e 100644 --- a/core/jni/android_opengl_GLES11.cpp +++ b/core/jni/android_opengl_GLES11.cpp @@ -29,15 +29,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -72,28 +63,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -104,23 +76,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -242,16 +208,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp index d28d9a387b5e..1144d5bfb4e6 100644 --- a/core/jni/android_opengl_GLES11Ext.cpp +++ b/core/jni/android_opengl_GLES11Ext.cpp @@ -29,15 +29,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -72,28 +63,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -104,23 +76,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -242,16 +208,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp index 0e20d474e275..2add72d14c7b 100644 --- a/core/jni/android_opengl_GLES20.cpp +++ b/core/jni/android_opengl_GLES20.cpp @@ -29,15 +29,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -72,28 +63,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -104,23 +76,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -242,16 +208,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp index 992239865db7..a9c021951758 100644 --- a/core/jni/android_opengl_GLES30.cpp +++ b/core/jni/android_opengl_GLES30.cpp @@ -29,15 +29,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -72,28 +63,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -104,23 +76,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -242,16 +208,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp index 27dbd399d77c..456da93784d5 100644 --- a/core/jni/android_opengl_GLES31.cpp +++ b/core/jni/android_opengl_GLES31.cpp @@ -27,15 +27,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -70,28 +61,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -102,23 +74,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -240,16 +206,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp index 5b671c8e55fb..dcaf4a58cd53 100644 --- a/core/jni/android_opengl_GLES31Ext.cpp +++ b/core/jni/android_opengl_GLES31Ext.cpp @@ -28,15 +28,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -71,28 +62,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -103,23 +75,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -241,16 +207,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp index d59d25c2c483..6bdc711d64a2 100644 --- a/core/jni/android_opengl_GLES32.cpp +++ b/core/jni/android_opengl_GLES32.cpp @@ -27,15 +27,6 @@ #include <utils/misc.h> #include <assert.h> -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -70,28 +61,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -102,23 +74,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -240,16 +206,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } // -------------------------------------------------------------------------- diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 3135c62c9c61..c0b31e49960b 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -271,8 +271,9 @@ static jobject nativeScreenshot(JNIEnv* env, jclass clazz, capturedSecureLayers); } -static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken, - jobject sourceCropObj, jfloat frameScale, jobjectArray excludeArray) { +static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj, + jobject layerHandleToken, jobject sourceCropObj, jfloat frameScale, + jobjectArray excludeArray) { sp<IBinder> layerHandle = ibinderForJavaObject(env, layerHandleToken); if (layerHandle == NULL) { @@ -301,7 +302,12 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandl } sp<GraphicBuffer> buffer; - const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB; + ui::Dataspace dataspace = ui::Dataspace::V0_SRGB; + sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); + if (displayToken != nullptr) { + const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken); + dataspace = pickDataspaceFromColorMode(colorMode); + } status_t res = ScreenshotClient::captureChildLayers(layerHandle, dataspace, ui::PixelFormat::RGBA_8888, sourceCrop, excludeHandles, frameScale, &buffer); @@ -1373,7 +1379,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { "Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;", (void*)nativeScreenshot }, {"nativeCaptureLayers", - "(Landroid/os/IBinder;Landroid/graphics/Rect;F[Landroid/os/IBinder;)" + "(Landroid/os/IBinder;Landroid/os/IBinder;Landroid/graphics/Rect;" + "F[Landroid/os/IBinder;)" "Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;", (void*)nativeCaptureLayers }, {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V", diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp index c806162c2534..6b893cb94444 100644 --- a/core/jni/com_google_android_gles_jni_GLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp @@ -65,16 +65,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); } -static jclass nioAccessClass; -static jclass bufferClass; static jclass G11ImplClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jmethodID allowIndirectBuffersID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; static jfieldID haveCheckedExtensionsID; static jfieldID have_OES_blend_equation_separateID; static jfieldID have_OES_blend_subtractID; @@ -86,12 +77,6 @@ static jfieldID have_OES_texture_cube_mapID; static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - jclass g11impClassLocal = _env->FindClass("com/google/android/gles_jni/GLImpl"); G11ImplClass = (jclass) _env->NewGlobalRef(g11impClassLocal); haveCheckedExtensionsID = _env->GetFieldID(G11ImplClass, "haveCheckedExtensions", "Z"); @@ -99,19 +84,6 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) have_OES_blend_subtractID = _env->GetFieldID(G11ImplClass, "have_OES_blend_subtract", "Z"); have_OES_framebuffer_objectID = _env->GetFieldID(G11ImplClass, "have_OES_framebuffer_object", "Z"); have_OES_texture_cube_mapID = _env->GetFieldID(G11ImplClass, "have_OES_texture_cube_map", "Z"); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - allowIndirectBuffersID = _env->GetStaticMethodID(g11impClassLocal, - "allowIndirectBuffers", "(Ljava/lang/String;)Z"); - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -122,28 +94,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *offset = 0; - *array = NULL; - return reinterpret_cast<void *>(pointer); - } - - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - if (*array == NULL) { - *offset = 0; - return (void*) NULL; + *array = nullptr; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } static void @@ -157,42 +118,24 @@ extern "C" { extern char* __progname; } -static bool -allowIndirectBuffers(JNIEnv *_env) { - static jint sIndirectBufferCompatability; - if (sIndirectBufferCompatability == 0) { - jobject appName = _env->NewStringUTF(::__progname); - sIndirectBufferCompatability = _env->CallStaticBooleanMethod(G11ImplClass, allowIndirectBuffersID, appName) ? 2 : 1; - } - return sIndirectBufferCompatability == 2; -} - static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - if (!buffer) { - return NULL; - } - void* buf = _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf = ((char*) buf) + (position << elementSizeShift); - } else { - if (allowIndirectBuffers(_env)) { - jarray array = 0; - jint remaining; - jint offset; - buf = getPointer(_env, buffer, &array, &remaining, &offset); - if (array) { - releasePointer(_env, array, buf, 0); - } - buf = (char*)buf + offset; - } else { - jniThrowException(_env, "java/lang/IllegalArgumentException", - "Must use a native order direct Buffer"); - } + if (buffer == nullptr) { + return nullptr; } - return buf; + + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { + jniThrowException(_env, "java/lang/IllegalArgumentException", + "Must use a native order direct Buffer"); + return nullptr; + } + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); } static int 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.xml b/core/res/res/layout/chooser_grid.xml index 1f8041741b46..68c62a6ebf3e 100644 --- a/core/res/res/layout/chooser_grid.xml +++ b/core/res/res/layout/chooser_grid.xml @@ -32,11 +32,11 @@ <ImageView android:id="@+id/drag" - android:layout_width="32dp" + android:layout_width="24dp" android:layout_height="4dp" android:src="@drawable/ic_drag_handle" android:clickable="true" - android:layout_marginTop="@dimen/chooser_view_spacing" + android:layout_marginTop="@dimen/chooser_edge_margin_thin" android:tint="@color/lighter_gray" android:layout_centerHorizontal="true" android:layout_alignParentTop="true" /> @@ -61,8 +61,9 @@ android:layout_width="wrap_content" android:textAppearance="?attr/textAppearanceMedium" android:textSize="20sp" + android:textColor="?attr/textColorPrimary" android:gravity="center" - android:paddingTop="@dimen/chooser_view_spacing" + android:paddingTop="@dimen/chooser_edge_margin_thin" android:paddingBottom="@dimen/chooser_view_spacing" android:paddingLeft="24dp" android:paddingRight="24dp" diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml index 6abf57a0f9f2..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,26 +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="24dp" + android:textColor="?android:attr/textColorPrimary" android:maxLines="2"/> - <Button + + <LinearLayout android:id="@+id/copy_button" - android:layout_width="24dp" - android:layout_height="24dp" + 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:foreground="@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 --> @@ -63,8 +88,8 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="horizontal" - android:layout_marginLeft="@dimen/chooser_edge_margin_thin" - android:layout_marginRight="@dimen/chooser_edge_margin_thin" + android:layout_marginLeft="@dimen/chooser_edge_margin_normal" + android:layout_marginRight="@dimen/chooser_edge_margin_normal" android:minHeight="80dp" android:background="@drawable/chooser_content_preview_rounded" android:id="@+id/content_preview_title_layout"> @@ -87,7 +112,8 @@ android:layout_gravity="center_vertical" android:ellipsize="end" android:maxLines="2" - android:textAppearance="?attr/textAppearanceMedium"/> + android:textSize="20sp" + android:textColor="?android:attr/textColorPrimary"/> </LinearLayout> </LinearLayout> diff --git a/core/res/res/layout/chooser_row.xml b/core/res/res/layout/chooser_row.xml index 742d7eedaced..f5814c3251f6 100644 --- a/core/res/res/layout/chooser_row.xml +++ b/core/res/res/layout/chooser_row.xml @@ -20,9 +20,7 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="100dp" - android:gravity="start|top" - android:paddingStart="@dimen/chooser_edge_margin_normal" - android:paddingEnd="@dimen/chooser_edge_margin_normal"> + android:gravity="start|top"> <TextView android:id="@+id/chooser_row_text_option" android:layout_width="match_parent" diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml index 7065149e268e..256d94e5c330 100644 --- a/core/res/res/layout/resolve_grid_item.xml +++ b/core/res/res/layout/resolve_grid_item.xml @@ -24,8 +24,8 @@ android:gravity="center" android:paddingTop="24dp" android:paddingBottom="8dp" - android:paddingLeft="2dp" - android:paddingRight="2dp" + android:paddingLeft="12dp" + android:paddingRight="12dp" android:focusable="true" android:background="?attr/selectableItemBackgroundBorderless"> @@ -45,7 +45,6 @@ android:textAppearance="?attr/textAppearanceSmall" android:textColor="?attr/textColorPrimary" android:textSize="14sp" - android:fontFamily="sans-serif-condensed" android:gravity="top|center_horizontal" android:lines="1" android:ellipsize="end" /> @@ -54,6 +53,7 @@ <TextView android:id="@android:id/text2" android:textAppearance="?android:attr/textAppearanceSmall" android:textSize="12sp" + android:textColor="?attr/textColorSecondary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:lines="1" diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index a5104242c71c..ab9a298f3060 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2104,9 +2104,8 @@ <p>If the app does not target at least {@link android.os.Build.VERSION_CODES#Q Q}, this attribute is ignored. - @see android.view.Window#setEnsureStatusBarContrastWhenTransparent - @hide pendingAPI --> - <attr name="ensureStatusBarContrastWhenTransparent" format="boolean" /> + @see android.view.Window#setEnsuringStatusBarContrastWhenTransparent --> + <attr name="ensuringStatusBarContrastWhenTransparent" format="boolean" /> <!-- Sets whether the system should ensure that the navigation bar has enough contrast when a fully transparent background is requested. @@ -2121,9 +2120,8 @@ <p>If the app does not target at least {@link android.os.Build.VERSION_CODES#Q Q}, this attribute is ignored. - @see android.view.Window#setEnsureNavigationBarContrastWhenTransparent - @hide pendingApi --> - <attr name="ensureNavigationBarContrastWhenTransparent" format="boolean" /> + @see android.view.Window#setEnsuringNavigationBarContrastWhenTransparent --> + <attr name="ensuringNavigationBarContrastWhenTransparent" format="boolean" /> <!-- The duration, in milliseconds, of the window background fade duration when transitioning into or away from an Activity when called with an @@ -2487,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 @@ -9014,10 +8995,10 @@ <!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar color. --> <attr name="navigationBarColor"/> - <!-- @hide From Window.ensureStatusBarContrastWhenTransparent --> - <attr name="ensureStatusBarContrastWhenTransparent"/> - <!-- @hide From Window.ensureNavigationBarContrastWhenTransparent --> - <attr name="ensureNavigationBarContrastWhenTransparent"/> + <!-- @hide From Window.ensuringStatusBarContrastWhenTransparent --> + <attr name="ensuringStatusBarContrastWhenTransparent"/> + <!-- @hide From Window.ensuringNavigationBarContrastWhenTransparent --> + <attr name="ensuringNavigationBarContrastWhenTransparent"/> </declare-styleable> <declare-styleable name="Shortcut"> 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 58afe33b2d36..4d6fda980755 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 --> @@ -3261,7 +3257,7 @@ <dimen name="config_backGestureInset">0dp</dimen> <!-- Controls whether the navbar needs a scrim with - {@link Window#setEnsureNavigationBarContrastWhenTransparent}. --> + {@link Window#setEnsuringNavigationBarContrastWhenTransparent}. --> <bool name="config_navBarNeedsScrim">true</bool> <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows. @@ -3487,6 +3483,12 @@ <item>com.android.messaging</item> </string-array> + <!-- An array of packages that can make sound on the ringer stream in priority-only DND + mode --> + <string-array translatable="false" name="config_priorityOnlyDndExemptPackages"> + <item>com.android.dialer</item> + </string-array> + <!-- An array of packages which can listen for notifications on low ram devices. --> <string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" /> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 02cbc2e578cf..b81db158082c 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -728,6 +728,6 @@ <dimen name="chooser_preview_width">-1px</dimen> <dimen name="resolver_icon_size">42dp</dimen> <dimen name="resolver_badge_size">18dp</dimen> - <dimen name="chooser_target_width">76dp</dimen> + <dimen name="chooser_target_width">90dp</dimen> <dimen name="chooser_max_collapsed_height">288dp</dimen> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 3bbc03f17efc..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" /> @@ -2943,6 +2943,9 @@ <public name="allowAudioPlaybackCapture"/> <public name="secureElementName" /> <public name="allowExternalStorageSandbox"/> + <public name="ensuringStatusBarContrastWhenTransparent" /> + <public name="ensuringNavigationBarContrastWhenTransparent" /> + <public name="identifier" /> </public-group> <public-group type="drawable" first-id="0x010800b4"> @@ -2985,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/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e9ce6ac93973..924b036813a6 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3188,6 +3188,7 @@ <java-symbol type="array" name="config_convert_to_emergency_number_map" /> <java-symbol type="array" name="config_nonBlockableNotificationPackages" /> + <java-symbol type="array" name="config_priorityOnlyDndExemptPackages" /> <java-symbol type="array" name="config_allowedManagedServicesOnLowRamDevices" /> @@ -3751,4 +3752,9 @@ <!-- For DropBox --> <java-symbol type="integer" name="config_dropboxLowPriorityBroadcastRateLimitPeriod" /> <java-symbol type="array" name="config_dropboxLowPriorityTags" /> + + <!-- For Privacy Type --> + <java-symbol type="drawable" name="perm_group_camera" /> + <java-symbol type="drawable" name="perm_group_location" /> + <java-symbol type="drawable" name="perm_group_microphone" /> </resources> 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..2280cf1cccfa 100644 --- a/core/tests/coretests/src/android/graphics/BitmapTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapTest.java @@ -22,6 +22,10 @@ import androidx.test.filters.SmallTest; import junit.framework.TestCase; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; + public class BitmapTest extends TestCase { @SmallTest @@ -262,4 +266,231 @@ public class BitmapTest extends TestCase { assertFalse(hardwareBitmap.isMutable()); assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), hardwareBitmap.getColorSpace()); } + + @SmallTest + public void testCopyWithDirectByteBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 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 bytesPerElement = 1; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + 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 * bytesPerPixel / bytesPerElement); + + // 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 testCopyWithDirectShortBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 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 short padValue = 0x55aa; + final int bytesPerElement = 2; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + ShortBuffer directBuffer = + ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asShortBuffer(); + + // 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 * bytesPerPixel / bytesPerElement); + + // Check padding + assertEquals(directBuffer.get(0), padValue); + assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); + + // Create bitmap from heap 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 testCopyWithDirectIntBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 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 int padValue = 0x55aa5a5a; + final int bytesPerElement = 4; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + IntBuffer directBuffer = + ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asIntBuffer(); + + // 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 * bytesPerPixel / bytesPerElement); + + // Check padding + assertEquals(directBuffer.get(0), padValue); + assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); + + // Create bitmap from heap 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 testCopyWithHeapByteBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 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 bytesPerElement = 1; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + 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 * bytesPerPixel / bytesPerElement); + + // 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)); + } + + @SmallTest + public void testCopyWithHeapShortBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 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 short padValue = 0x55aa; + final int bytesPerElement = 2; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + ShortBuffer heapBuffer = ShortBuffer.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 * bytesPerPixel / bytesPerElement); + + // 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)); + } + + @SmallTest + public void testCopyWithHeapIntBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + final int bytesPerPixel = 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 int padValue = 0x55aa5a5a; + final int bytesPerElement = 4; + final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; + IntBuffer heapBuffer = IntBuffer.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 * bytesPerPixel / bytesPerElement); + + // 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 655070722c9a..0e94abc0dcac 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -708,7 +708,10 @@ public class SettingsBackupTest { Settings.Secure.FLASHLIGHT_ENABLED, Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, Settings.Secure.LOCATION_ACCESS_CHECK_INTERVAL_MILLIS, - Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS); + Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS, + 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/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index 433991e86212..aeb8949c6976 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -362,6 +362,38 @@ public class TextClassifierTest { } @Test + public void testGenerateLinks_entityData() { + if (isTextClassifierDisabled()) return; + String text = "The number is +12122537077."; + Bundle extras = new Bundle(); + ExtrasUtils.putIsSerializedEntityDataEnabled(extras, true); + TextLinks.Request request = new TextLinks.Request.Builder(text).setExtras(extras).build(); + + TextLinks textLinks = mClassifier.generateLinks(request); + + Truth.assertThat(textLinks.getLinks()).hasSize(1); + TextLinks.TextLink textLink = textLinks.getLinks().iterator().next(); + List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras()); + Truth.assertThat(entities).hasSize(1); + Bundle entity = entities.get(0); + Truth.assertThat(ExtrasUtils.getEntityType(entity)).isEqualTo(TextClassifier.TYPE_PHONE); + } + + @Test + public void testGenerateLinks_entityData_disabled() { + if (isTextClassifierDisabled()) return; + String text = "The number is +12122537077."; + TextLinks.Request request = new TextLinks.Request.Builder(text).build(); + + TextLinks textLinks = mClassifier.generateLinks(request); + + Truth.assertThat(textLinks.getLinks()).hasSize(1); + TextLinks.TextLink textLink = textLinks.getLinks().iterator().next(); + List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras()); + Truth.assertThat(entities).isNull(); + } + + @Test public void testDetectLanguage() { if (isTextClassifierDisabled()) return; String text = "This is English text"; @@ -380,7 +412,7 @@ public class TextClassifierTest { } @Test - public void testSuggestConversationActions_textReplyOnly_maxThree() { + public void testSuggestConversationActions_textReplyOnly_maxOne() { if (isTextClassifierDisabled()) return; ConversationActions.Message message = new ConversationActions.Message.Builder( @@ -399,12 +431,11 @@ public class TextClassifierTest { .build(); ConversationActions conversationActions = mClassifier.suggestConversationActions(request); - assertTrue(conversationActions.getConversationActions().size() > 0); - for (ConversationAction conversationAction : - conversationActions.getConversationActions()) { - assertThat(conversationAction, - isConversationAction(ConversationAction.TYPE_TEXT_REPLY)); - } + Truth.assertThat(conversationActions.getConversationActions()).hasSize(1); + ConversationAction conversationAction = conversationActions.getConversationActions().get(0); + Truth.assertThat(conversationAction.getType()).isEqualTo( + ConversationAction.TYPE_TEXT_REPLY); + Truth.assertThat(conversationAction.getTextReply()).isNotNull(); } @Test @@ -493,6 +524,24 @@ public class TextClassifierTest { ExtrasUtils.getSerializedEntityData(conversationAction.getExtras())).isNotEmpty(); } + @Test + public void testSuggetsConversationActions_deduplicate() { + if (isTextClassifierDisabled()) return; + ConversationActions.Message message = + new ConversationActions.Message.Builder( + ConversationActions.Message.PERSON_USER_OTHERS) + .setText("a@android.com b@android.com") + .build(); + ConversationActions.Request request = + new ConversationActions.Request.Builder(Collections.singletonList(message)) + .setMaxSuggestions(3) + .build(); + + ConversationActions conversationActions = mClassifier.suggestConversationActions(request); + + Truth.assertThat(conversationActions.getConversationActions()).isEmpty(); + } + private boolean isTextClassifierDisabled() { return mClassifier == null || mClassifier == TextClassifier.NO_OP; } diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java index 1980a604fdd2..2c540e560f6b 100644 --- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java @@ -49,8 +49,6 @@ import org.mockito.MockitoAnnotations; public class TextClassifierEventTronLoggerTest { private static final String WIDGET_TYPE = "notification"; private static final String PACKAGE_NAME = "pkg"; - private static final long EVENT_TIME = System.currentTimeMillis(); - @Mock private MetricsLogger mMetricsLogger; @@ -68,13 +66,11 @@ public class TextClassifierEventTronLoggerTest { TextClassificationContext textClassificationContext = new TextClassificationContext.Builder(PACKAGE_NAME, WIDGET_TYPE) .build(); - TextClassifierEvent textClassifierEvent = - new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, + TextClassifierEvent.ConversationActionsEvent textClassifierEvent = + new TextClassifierEvent.ConversationActionsEvent.Builder( TextClassifierEvent.TYPE_SMART_ACTION) .setEntityTypes(ConversationAction.TYPE_CALL_PHONE) - .setScore(0.5f) - .setEventTime(EVENT_TIME) + .setScores(0.5f) .setEventContext(textClassificationContext) .build(); @@ -83,10 +79,8 @@ public class TextClassifierEventTronLoggerTest { ArgumentCaptor<LogMaker> captor = ArgumentCaptor.forClass(LogMaker.class); Mockito.verify(mMetricsLogger).write(captor.capture()); LogMaker logMaker = captor.getValue(); - assertThat(logMaker.getCategory()).isEqualTo( - CONVERSATION_ACTIONS); - assertThat(logMaker.getSubtype()).isEqualTo( - ACTION_TEXT_SELECTION_SMART_SHARE); + assertThat(logMaker.getCategory()).isEqualTo(CONVERSATION_ACTIONS); + assertThat(logMaker.getSubtype()).isEqualTo(ACTION_TEXT_SELECTION_SMART_SHARE); assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE)) .isEqualTo(ConversationAction.TYPE_CALL_PHONE); assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE)) @@ -101,9 +95,8 @@ public class TextClassifierEventTronLoggerTest { @Test public void testWriteEvent_unsupportedCategory() { - TextClassifierEvent textClassifierEvent = - new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_SELECTION, + TextClassifierEvent.TextSelectionEvent textClassifierEvent = + new TextClassifierEvent.TextSelectionEvent.Builder( TextClassifierEvent.TYPE_SMART_ACTION) .build(); 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..70dacb20cde7 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -20,10 +20,6 @@ java_library { ], }, - static_libs: [ - "mediaplayer2-protos", - ], - permitted_packages: [ "android.media", ], @@ -43,7 +39,6 @@ filegroup { name: "updatable-media-srcs", srcs: [ ":mediasession2-srcs", - ":mediaplayer2-srcs", ], } @@ -51,7 +46,6 @@ filegroup { name: "updatable-media-srcs-without-aidls", srcs : [ ":mediasession2-srcs-without-aidls", - ":mediaplayer2-srcs", ], } @@ -64,7 +58,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", @@ -110,8 +103,7 @@ metalava_updatable_media_args = " --error UnhiddenSystemApi " + "--hide MissingPermission --hide BroadcastBehavior " + "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " + - "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi " + - " --show-annotation android.annotation.TestApi " + "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi " droidstubs { name: "updatable-media-stubs", diff --git a/media/apex/java/android/media/BufferingParams.java b/media/apex/java/android/media/BufferingParams.java index 83594d474b37..943f14277fc3 100644 --- a/media/apex/java/android/media/BufferingParams.java +++ b/media/apex/java/android/media/BufferingParams.java @@ -17,7 +17,6 @@ package android.media; import android.annotation.IntDef; -import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -64,7 +63,6 @@ import java.lang.annotation.RetentionPolicy; * <p>Users should use {@link Builder} to change {@link BufferingParams}. * @hide */ -@TestApi public final class BufferingParams implements Parcelable { private static final int BUFFERING_NO_MARK = -1; 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 9d4bce7b4301..e655460c2ba1 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; import android.os.Build; import android.os.Bundle; import android.os.Parcel; @@ -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}, @@ -783,9 +807,10 @@ public final class AudioAttributes implements Parcelable { */ @UnsupportedAppUsage public Builder setInternalLegacyStreamType(int streamType) { - final AudioProductStrategies ps = new AudioProductStrategies(); - if (ps.size() > 0) { - AudioAttributes attributes = ps.getAudioAttributesForLegacyStreamType(streamType); + if (AudioProductStrategy.getAudioProductStrategies().size() > 0) { + AudioAttributes attributes = + AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( + streamType); if (attributes != null) { return new Builder(attributes); } @@ -1165,9 +1190,8 @@ public final class AudioAttributes implements Parcelable { AudioSystem.STREAM_MUSIC : AudioSystem.STREAM_TTS; } - final AudioProductStrategies ps = new AudioProductStrategies(); - if (ps.size() > 0) { - return ps.getLegacyStreamTypeForAudioAttributes(aa); + if (AudioProductStrategy.getAudioProductStrategies().size() > 0) { + return AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(aa); } // usage to stream type mapping switch (aa.getUsage()) { 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 dc5c6639375b..f8e43437d244 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -25,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; @@ -36,9 +38,9 @@ import android.content.Context; import android.content.Intent; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; import android.media.audiopolicy.AudioVolumeGroupChangeHandler; -import android.media.audiopolicy.AudioVolumeGroups; import android.media.projection.MediaProjection; import android.media.session.MediaController; import android.media.session.MediaSession; @@ -1204,6 +1206,7 @@ public class AudioManager { * @hide */ @SystemApi + @IntRange(from = 0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { Preconditions.checkNotNull(attr, "attr must not be null"); @@ -1224,6 +1227,7 @@ public class AudioManager { * @hide */ @SystemApi + @IntRange(from = 0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { Preconditions.checkNotNull(attr, "attr must not be null"); @@ -1244,6 +1248,7 @@ public class AudioManager { * @hide */ @SystemApi + @IntRange(from = 0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { Preconditions.checkNotNull(attr, "attr must not be null"); @@ -1479,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}, @@ -1499,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; } //==================================================================== @@ -3022,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, @@ -3061,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, @@ -3323,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) { @@ -3357,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) { @@ -3383,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) { @@ -3397,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 /** @@ -4475,6 +4523,7 @@ public class AudioManager { */ /** @hide */ + @TestApi @SystemApi public static final int SUCCESS = AudioSystem.SUCCESS; /** @@ -5402,8 +5451,9 @@ public class AudioManager { * {@see android.media.audiopolicy.AudioProductStrategy} objects. */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @NonNull AudioProductStrategies getAudioProductStrategies() { + public static List<AudioProductStrategy> getAudioProductStrategies() { final IAudioService service = getService(); try { return service.getAudioProductStrategies(); @@ -5417,15 +5467,16 @@ public class AudioManager { * Introspection API to retrieve audio volume groups. * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of * audio volume groups. - * @return a (possibly zero-length) array of - * {@see android.media.audiopolicy.AudioVolumeGroups} objects. + * @return a (possibly zero-length) List of + * {@see android.media.audiopolicy.AudioVolumeGroup} objects. */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @NonNull AudioVolumeGroups getAudioVolumeGroups() { + public static List<AudioVolumeGroup> getAudioVolumeGroups() { final IAudioService service = getService(); try { - return service.listAudioVolumeGroups(); + return service.getAudioVolumeGroups(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } 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 980cb0459821..85de00a2a989 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -33,8 +33,8 @@ import android.media.IVolumeController; import android.media.PlayerBase; import android.media.VolumePolicy; import android.media.audiopolicy.AudioPolicyConfig; -import android.media.audiopolicy.AudioProductStrategies; -import android.media.audiopolicy.AudioVolumeGroups; +import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; import android.net.Uri; @@ -86,7 +86,7 @@ interface IAudioService { @UnsupportedAppUsage int getStreamMaxVolume(int streamType); - AudioVolumeGroups listAudioVolumeGroups(); + List<AudioVolumeGroup> getAudioVolumeGroups(); void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags, String callingPackage); @@ -98,7 +98,7 @@ interface IAudioService { int getLastAudibleStreamVolume(int streamType); - AudioProductStrategies getAudioProductStrategies(); + List<AudioProductStrategy> getAudioProductStrategies(); void setMicrophoneMute(boolean on, String callingPackage, int userId); @@ -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/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index fefb0d7a55bf..e207721f1918 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -495,15 +495,17 @@ public class RingtoneManager { if (mCursor == null || !mCursor.moveToPosition(position)) { return null; } - - return getUriFromCursor(mCursor); + + return getUriFromCursor(mContext, mCursor); } - private static Uri getUriFromCursor(Cursor cursor) { - return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor - .getLong(ID_COLUMN_INDEX)); + private static Uri getUriFromCursor(Context context, Cursor cursor) { + final Uri uri = ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), + cursor.getLong(ID_COLUMN_INDEX)); + final Uri canonicalized = context.getContentResolver().canonicalize(uri); + return (canonicalized != null) ? canonicalized : uri; } - + /** * Gets the position of a {@link Uri} within this {@link RingtoneManager}. * @@ -569,7 +571,7 @@ public class RingtoneManager { Uri uri = null; if (cursor.moveToFirst()) { - uri = getUriFromCursor(cursor); + uri = getUriFromCursor(context, cursor); } cursor.close(); 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..39474e13a2d0 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; @@ -412,6 +416,7 @@ public class AudioPolicy { * @param devices list of devices to which the audio stream of the application may be routed. * @return true if the change was successful, false otherwise. */ + @TestApi @SystemApi public boolean setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) { if (devices == null) { @@ -453,6 +458,7 @@ public class AudioPolicy { * @param uid UID of the application affected. * @return true if the change was successful, false otherwise. */ + @TestApi @SystemApi public boolean removeUidDeviceAffinity(int uid) { synchronized (mLock) { diff --git a/media/java/android/media/audiopolicy/AudioProductStrategies.aidl b/media/java/android/media/audiopolicy/AudioProductStrategies.aidl deleted file mode 100644 index bec11bcfab5d..000000000000 --- a/media/java/android/media/audiopolicy/AudioProductStrategies.aidl +++ /dev/null @@ -1,18 +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.audiopolicy; - -parcelable AudioProductStrategies; diff --git a/media/java/android/media/audiopolicy/AudioProductStrategies.java b/media/java/android/media/audiopolicy/AudioProductStrategies.java deleted file mode 100644 index c305b683f136..000000000000 --- a/media/java/android/media/audiopolicy/AudioProductStrategies.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media.audiopolicy; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.media.AudioAttributes; -import android.media.AudioSystem; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import com.android.internal.util.Preconditions; - -import java.util.ArrayList; -import java.util.Iterator; - -/** - * @hide - * A class to encapsulate a collection of {@link AudioProductStrategy}. - * Provides helper functions to easily retrieve the {@link AudioAttributes} for a given product - * strategy or legacy stream type. - */ -@SystemApi -public final class AudioProductStrategies implements Iterable<AudioProductStrategy>, Parcelable { - - private final ArrayList<AudioProductStrategy> mAudioProductStrategyList; - - private static final String TAG = "AudioProductStrategies"; - - public AudioProductStrategies() { - ArrayList<AudioProductStrategy> apsList = new ArrayList<AudioProductStrategy>(); - int status = native_list_audio_product_strategies(apsList); - if (status != AudioSystem.SUCCESS) { - Log.w(TAG, ": createAudioProductStrategies failed"); - } - mAudioProductStrategyList = apsList; - } - - private AudioProductStrategies(ArrayList<AudioProductStrategy> audioProductStrategy) { - mAudioProductStrategyList = audioProductStrategy; - } - - /** - * @hide - * @return number of {@link AudioProductStrategy} objects - */ - @SystemApi - public int size() { - return mAudioProductStrategyList.size(); - } - - /** - * @hide - * @return the matching {@link AudioProductStrategy} objects with the given id, - * null object if not found. - */ - @SystemApi - public @Nullable AudioProductStrategy getById(int productStrategyId) { - for (final AudioProductStrategy avg : this) { - if (avg.getId() == productStrategyId) { - return avg; - } - } - Log.e(TAG, ": invalid product strategy id: " + productStrategyId + " requested"); - return null; - } - - /** - * Returns an {@link Iterator} - */ - @Override - public @NonNull Iterator<AudioProductStrategy> iterator() { - return mAudioProductStrategyList.iterator(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - AudioProductStrategies that = (AudioProductStrategies) o; - - return mAudioProductStrategyList.equals(that.mAudioProductStrategyList); - } - - /** - * @hide - * @param aps {@link AudioProductStrategy} (which is the generalisation of Car Audio Usage / - * legacy routing_strategy linked to {@link AudioAttributes#getUsage()} ) - * @return the {@link AudioAttributes} relevant for the given product strategy. - * If none is found, it builds the default attributes. - * TODO: shall the helper collection be able to identify the platform default? - */ - @SystemApi - @NonNull - public AudioAttributes getAudioAttributesForProductStrategy(@NonNull AudioProductStrategy aps) { - Preconditions.checkNotNull(aps, "AudioProductStrategy must not be null"); - for (final AudioProductStrategy audioProductStrategy : this) { - if (audioProductStrategy.equals(aps)) { - return audioProductStrategy.getAudioAttributes(); - } - } - return new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) - .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); - } - - /** - * @hide - * @param streamType legacy stream type used for volume operation only - * @return the {@link AudioAttributes} relevant for the given streamType. - * If none is found, it builds the default attributes. - */ - @SystemApi - public @NonNull AudioAttributes getAudioAttributesForLegacyStreamType(int streamType) { - for (final AudioProductStrategy productStrategy : this) { - AudioAttributes aa = productStrategy.getAudioAttributesForLegacyStreamType(streamType); - if (aa != null) { - return aa; - } - } - return new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) - .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); - } - - /** - * @hide - * @param aa the {@link AudioAttributes} for which stream type is requested - * @return the legacy stream type relevant for the given {@link AudioAttributes}. - * If the product strategy is not associated to any stream, it returns - * {@link AudioSystem#STREAM_MUSIC}. - * If no product strategy supports the stream type, it returns - * {@link AudioSystem#STREAM_MUSIC}. - */ - @SystemApi - public int getLegacyStreamTypeForAudioAttributes(@NonNull AudioAttributes aa) { - Preconditions.checkNotNull(aa, "AudioAttributes must not be null"); - for (final AudioProductStrategy productStrategy : this) { - if (productStrategy.supportsAudioAttributes(aa)) { - int streamType = productStrategy.getLegacyStreamTypeForAudioAttributes(aa); - if (streamType == AudioSystem.STREAM_DEFAULT) { - Log.w(TAG, "Attributes " + aa.toString() + " ported by strategy " - + productStrategy.name() + " has no stream type associated, " - + "DO NOT USE STREAM TO CONTROL THE VOLUME"); - return AudioSystem.STREAM_MUSIC; - } - return streamType; - } - } - return AudioSystem.STREAM_MUSIC; - } - - /** - * @hide - * @param aa the {@link AudioAttributes} to be considered - * @return {@link AudioProductStrategy} supporting the given {@link AudioAttributes}. - * null is returned if no match with given attributes. - */ - @SystemApi - @Nullable - public AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull AudioAttributes aa) { - Preconditions.checkNotNull(aa, "attributes must not be null"); - int productStrategyId = native_get_product_strategies_from_audio_attributes(aa); - if (productStrategyId < 0) { - Log.w(TAG, "no strategy found for Attributes " + aa.toString()); - return null; - } - return getById(productStrategyId); - } - - /** - * @hide - * @param attributes the {@link AudioAttributes} to be considered - * @return volume group associated to the given {@link AudioAttributes}. - * If no group supports the given {@link AudioAttributes}, it returns the volume group - * for the default attributes. - * If no group supports the default attributes, it returns {@link #DEFAULT_VOLUME_GROUP} - */ - @SystemApi - public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { - Preconditions.checkNotNull(attributes, "attributes must not be null"); - int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { - return volumeGroupId; - } - // The default volume group is the one hosted by default product strategy, i.e. - // supporting Default Attributes - return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); - } - - /** - * @hide - * @param streamType to be considered - * @return volume group associated to the given stream type. - */ - @SystemApi - public int getVolumeGroupIdForLegacyStreamType(int streamType) { - for (final AudioProductStrategy productStrategy : this) { - int volumeGroupId = productStrategy.getVolumeGroupIdForLegacyStreamType(streamType); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { - return volumeGroupId; - } - } - // The default volume group is the one hosted by default product strategy, i.e. - // supporting Default Attributes - return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(size()); - for (final AudioProductStrategy productStrategy : this) { - productStrategy.writeToParcel(dest, flags); - } - } - - /** - * @param attributes to be considered - * @return volume group associated to the given {@link AudioAttributes}. - */ - private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) { - Preconditions.checkNotNull(attributes, "attributes must not be null"); - for (final AudioProductStrategy productStrategy : this) { - int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { - return volumeGroupId; - } - } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; - } - - public static final @android.annotation.NonNull Parcelable.Creator<AudioProductStrategies> CREATOR = - new Parcelable.Creator<AudioProductStrategies>() { - @Override - public AudioProductStrategies createFromParcel(@NonNull Parcel in) { - ArrayList<AudioProductStrategy> apsList = new ArrayList<AudioProductStrategy>(); - int size = in.readInt(); - for (int index = 0; index < size; index++) { - apsList.add(AudioProductStrategy.CREATOR.createFromParcel(in)); - } - return new AudioProductStrategies(apsList); - } - - @Override - public @NonNull AudioProductStrategies[] newArray(int size) { - return new AudioProductStrategies[size]; - } - }; - - private static native int native_list_audio_product_strategies( - ArrayList<AudioProductStrategy> strategies); - - private static native int native_get_product_strategies_from_audio_attributes( - AudioAttributes attributes); -} diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java index c1c255f68996..9ac9411370ab 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategy.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java @@ -25,9 +25,14 @@ import android.media.MediaRecorder; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; +import java.util.ArrayList; +import java.util.List; + /** * @hide * A class to encapsulate a collection of attributes associated to a given product strategy @@ -41,6 +46,9 @@ public final class AudioProductStrategy implements Parcelable { */ public static final int DEFAULT_GROUP = -1; + + private static final String TAG = "AudioProductStrategy"; + private final AudioAttributesGroup[] mAudioAttributesGroups; private final String mName; /** @@ -51,6 +59,86 @@ public final class AudioProductStrategy implements Parcelable { */ private int mId; + private static final Object sLock = new Object(); + + @GuardedBy("sLock") + private static List<AudioProductStrategy> sAudioProductStrategies; + + /** + * @hide + * @return the list of AudioProductStrategy discovered from platform configuration file. + */ + @NonNull + public static List<AudioProductStrategy> getAudioProductStrategies() { + if (sAudioProductStrategies == null) { + synchronized (sLock) { + if (sAudioProductStrategies == null) { + sAudioProductStrategies = initializeAudioProductStrategies(); + } + } + } + return sAudioProductStrategies; + } + + /** + * @hide + * @param streamType to match against AudioProductStrategy + * @return the AudioAttributes for the first strategy found with the associated stream type + * If no match is found, returns AudioAttributes with unknown content_type and usage + */ + @NonNull + public static AudioAttributes getAudioAttributesForStrategyWithLegacyStreamType( + int streamType) { + for (final AudioProductStrategy productStrategy : + AudioProductStrategy.getAudioProductStrategies()) { + AudioAttributes aa = productStrategy.getAudioAttributesForLegacyStreamType(streamType); + if (aa != null) { + return aa; + } + } + return new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) + .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); + } + + /** + * @hide + * @param audioAttributes to identify AudioProductStrategy with + * @return legacy stream type associated with matched AudioProductStrategy + * Defaults to STREAM_MUSIC if no match is found, or if matches is STREAM_DEFAULT + */ + public static int getLegacyStreamTypeForStrategyWithAudioAttributes( + @NonNull AudioAttributes audioAttributes) { + Preconditions.checkNotNull(audioAttributes, "AudioAttributes must not be null"); + for (final AudioProductStrategy productStrategy : + AudioProductStrategy.getAudioProductStrategies()) { + if (productStrategy.supportsAudioAttributes(audioAttributes)) { + int streamType = productStrategy.getLegacyStreamTypeForAudioAttributes( + audioAttributes); + if (streamType == AudioSystem.STREAM_DEFAULT) { + Log.w(TAG, "Attributes " + audioAttributes.toString() + " ported by strategy " + + productStrategy.getId() + " has no stream type associated, " + + "DO NOT USE STREAM TO CONTROL THE VOLUME"); + return AudioSystem.STREAM_MUSIC; + } + return streamType; + } + } + return AudioSystem.STREAM_MUSIC; + } + + private static List<AudioProductStrategy> initializeAudioProductStrategies() { + ArrayList<AudioProductStrategy> apsList = new ArrayList<AudioProductStrategy>(); + int status = native_list_audio_product_strategies(apsList); + if (status != AudioSystem.SUCCESS) { + Log.w(TAG, ": initializeAudioProductStrategies failed"); + } + return apsList; + } + + private static native int native_list_audio_product_strategies( + ArrayList<AudioProductStrategy> strategies); + @Override public boolean equals(@Nullable Object o) { if (this == o) return true; @@ -65,8 +153,7 @@ public final class AudioProductStrategy implements Parcelable { /** * @param name of the product strategy * @param id of the product strategy - * @param audioAttributes {@link AudioAttributes} associated to the given product strategy - * @param legacyStreamTypes associated to the given product strategy. + * @param aag {@link AudioAttributesGroup} associated to the given product strategy */ private AudioProductStrategy(@NonNull String name, int id, @NonNull AudioAttributesGroup[] aag) { @@ -79,15 +166,6 @@ public final class AudioProductStrategy implements Parcelable { /** * @hide - * @return human-readable name of this product strategy, which is similar to a usage - */ - @SystemApi - public @NonNull String name() { - return mName; - } - - /** - * @hide * @return the product strategy ID (which is the generalisation of Car Audio Usage / legacy * routing_strategy linked to {@link AudioAttributes#getUsage()}). */ @@ -158,7 +236,7 @@ public final class AudioProductStrategy implements Parcelable { * @hide * @param streamType legacy stream type used for volume operation only * @return the volume group id relevant for the given streamType. - * If none is found, {@link AudioVolumeGroups#DEFAULT_VOLUME_GROUP} is returned. + * If none is found, {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} is returned. */ public int getVolumeGroupIdForLegacyStreamType(int streamType) { for (final AudioAttributesGroup aag : mAudioAttributesGroups) { @@ -166,14 +244,14 @@ public final class AudioProductStrategy implements Parcelable { return aag.getVolumeGroupId(); } } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + return AudioVolumeGroup.DEFAULT_VOLUME_GROUP; } /** * @hide * @param aa the {@link AudioAttributes} to be considered * @return the volume group id associated with the given audio attributes if found, - * {@link AudioVolumeGroups#DEFAULT_VOLUME_GROUP} otherwise. + * {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} otherwise. */ public int getVolumeGroupIdForAudioAttributes(@NonNull AudioAttributes aa) { Preconditions.checkNotNull(aa, "AudioAttributes must not be null"); @@ -182,7 +260,7 @@ public final class AudioProductStrategy implements Parcelable { return aag.getVolumeGroupId(); } } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + return AudioVolumeGroup.DEFAULT_VOLUME_GROUP; } @Override @@ -200,7 +278,8 @@ public final class AudioProductStrategy implements Parcelable { } } - public static final @android.annotation.NonNull Parcelable.Creator<AudioProductStrategy> CREATOR = + @NonNull + public static final Parcelable.Creator<AudioProductStrategy> CREATOR = new Parcelable.Creator<AudioProductStrategy>() { @Override public AudioProductStrategy createFromParcel(@NonNull Parcel in) { diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroup.java b/media/java/android/media/audiopolicy/AudioVolumeGroup.java index b60947f13c1f..79be92214455 100644 --- a/media/java/android/media/audiopolicy/AudioVolumeGroup.java +++ b/media/java/android/media/audiopolicy/AudioVolumeGroup.java @@ -19,11 +19,15 @@ package android.media.audiopolicy; import android.annotation.NonNull; import android.annotation.SystemApi; import android.media.AudioAttributes; +import android.media.AudioSystem; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -34,6 +38,12 @@ import java.util.List; */ @SystemApi public final class AudioVolumeGroup implements Parcelable { + private static final String TAG = "AudioVolumeGroup"; + /** + * Volume group value to use when introspection API fails. + */ + public static final int DEFAULT_VOLUME_GROUP = -1; + /** * Unique identifier of a volume group. */ @@ -46,10 +56,43 @@ public final class AudioVolumeGroup implements Parcelable { private final AudioAttributes[] mAudioAttributes; private int[] mLegacyStreamTypes; + private static final Object sLock = new Object(); + + @GuardedBy("sLock") + private static List<AudioVolumeGroup> sAudioVolumeGroups; + + /** + * @hide + * @return the List of AudioVolumeGroup discovered from platform configuration file. + */ + @NonNull + public static List<AudioVolumeGroup> getAudioVolumeGroups() { + if (sAudioVolumeGroups == null) { + synchronized (sLock) { + if (sAudioVolumeGroups == null) { + sAudioVolumeGroups = initializeAudioVolumeGroups(); + } + } + } + return sAudioVolumeGroups; + } + + private static List<AudioVolumeGroup> initializeAudioVolumeGroups() { + ArrayList<AudioVolumeGroup> avgList = new ArrayList<>(); + int status = native_list_audio_volume_groups(avgList); + if (status != AudioSystem.SUCCESS) { + Log.w(TAG, ": listAudioVolumeGroups failed"); + } + return avgList; + } + + private static native int native_list_audio_volume_groups( + ArrayList<AudioVolumeGroup> groups); + /** * @param name of the volume group * @param id of the volume group - * @param followers {@link AudioProductStrategies} strategy following this volume group + * @param legacyStreamTypes of volume group */ AudioVolumeGroup(@NonNull String name, int id, @NonNull AudioAttributes[] audioAttributes, diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroups.aidl b/media/java/android/media/audiopolicy/AudioVolumeGroups.aidl deleted file mode 100644 index 918cac39f19a..000000000000 --- a/media/java/android/media/audiopolicy/AudioVolumeGroups.aidl +++ /dev/null @@ -1,18 +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.audiopolicy; - -parcelable AudioVolumeGroups; diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroups.java b/media/java/android/media/audiopolicy/AudioVolumeGroups.java deleted file mode 100644 index 2e56f846e574..000000000000 --- a/media/java/android/media/audiopolicy/AudioVolumeGroups.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media.audiopolicy; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.media.AudioSystem; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import com.android.internal.util.Preconditions; - -import java.util.ArrayList; -import java.util.Iterator; - -/** - * @hide - * A class to encapsulate a collection of {@link AudioVolumeGroup}. - */ -@SystemApi -public final class AudioVolumeGroups implements Iterable<AudioVolumeGroup>, Parcelable { - - private final ArrayList<AudioVolumeGroup> mAudioVolumeGroupList; - - private static final String TAG = "AudioVolumeGroups"; - - /** - * Volume group value to use when introspection API fails. - */ - public static final int DEFAULT_VOLUME_GROUP = -1; - - public AudioVolumeGroups() { - ArrayList<AudioVolumeGroup> avgList = new ArrayList<AudioVolumeGroup>(); - int status = native_list_audio_volume_groups(avgList); - if (status != AudioSystem.SUCCESS) { - Log.w(TAG, ": listAudioVolumeGroups failed"); - } - mAudioVolumeGroupList = avgList; - } - - private AudioVolumeGroups(@NonNull ArrayList<AudioVolumeGroup> audioVolumeGroupList) { - Preconditions.checkNotNull(audioVolumeGroupList, "audioVolumeGroupList must not be null"); - mAudioVolumeGroupList = audioVolumeGroupList; - } - - /** - * @return number of {@link AudioProductStrategy} objects - */ - public int size() { - return mAudioVolumeGroupList.size(); - } - - /** - * Returns an {@link Iterator} - */ - @Override - public @NonNull Iterator<AudioVolumeGroup> iterator() { - return mAudioVolumeGroupList.iterator(); - } - - @Override - public boolean equals(@NonNull Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - AudioVolumeGroups that = (AudioVolumeGroups) o; - - return mAudioVolumeGroupList.equals(that.mAudioVolumeGroupList); - } - - /** - * @return the matching {@link AudioVolumeGroup} objects with the given id, - * null object if not found. - */ - public @Nullable AudioVolumeGroup getById(int volumeGroupId) { - for (final AudioVolumeGroup avg : this) { - if (avg.getId() == volumeGroupId) { - return avg; - } - } - Log.e(TAG, ": invalid volume group id: " + volumeGroupId + " requested"); - return null; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(size()); - for (final AudioVolumeGroup volumeGroup : this) { - volumeGroup.writeToParcel(dest, flags); - } - } - - private static native int native_list_audio_volume_groups( - ArrayList<AudioVolumeGroup> groups); - - public static final Parcelable.Creator<AudioVolumeGroups> CREATOR = - new Parcelable.Creator<AudioVolumeGroups>() { - @Override - public @NonNull AudioVolumeGroups createFromParcel(@NonNull Parcel in) { - Preconditions.checkNotNull(in, "in Parcel must not be null"); - ArrayList<AudioVolumeGroup> avgList = new ArrayList<AudioVolumeGroup>(); - int size = in.readInt(); - for (int index = 0; index < size; index++) { - avgList.add(AudioVolumeGroup.CREATOR.createFromParcel(in)); - } - return new AudioVolumeGroups(avgList); - } - - @Override - public @NonNull AudioVolumeGroups[] newArray(int size) { - return new AudioVolumeGroups[size]; - } - }; -} 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..7860f36e7d95 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -238,7 +238,7 @@ public class Assistant extends NotificationAssistantService { } mSingleThreadExecutor.submit(() -> { NotificationEntry entry = - new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper); + new NotificationEntry(mPackageManager, sbn.cloneLight(), channel, mSmsHelper); SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry); if (DEBUG) { Log.d(TAG, String.format( @@ -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()); } } @@ -293,7 +296,7 @@ public class Assistant extends NotificationAssistantService { Ranking ranking = getRanking(sbn.getKey(), rankingMap); if (ranking != null && ranking.getChannel() != null) { NotificationEntry entry = new NotificationEntry(mPackageManager, - sbn, ranking.getChannel(), mSmsHelper); + sbn.cloneLight(), ranking.getChannel(), mSmsHelper); String key = getKey( sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId()); ChannelImpressions ci = mkeyToImpressions.getOrDefault(key, diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java index 0d687d41260d..10360a34546c 100644 --- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java +++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java @@ -338,7 +338,7 @@ public class SmartActionsHelper { createTextClassifierEventBuilder( TextClassifierEvent.TYPE_SMART_ACTION, session.resultId) .setEntityTypes(ConversationAction.TYPE_TEXT_REPLY) - .setScore(session.repliesScores.getOrDefault(reply, 0f)) + .setScores(session.repliesScores.getOrDefault(reply, 0f)) .build(); mTextClassifier.onTextClassifierEvent(textClassifierEvent); } @@ -381,11 +381,9 @@ public class SmartActionsHelper { .build(); } - private TextClassifierEvent.Builder createTextClassifierEventBuilder( + private TextClassifierEvent.ConversationActionsEvent.Builder createTextClassifierEventBuilder( int eventType, String resultId) { - return new TextClassifierEvent.Builder( - TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType) - .setEventTime(System.currentTimeMillis()) + return new TextClassifierEvent.ConversationActionsEvent.Builder(eventType) .setEventContext( new TextClassificationContext.Builder( mContext.getPackageName(), TextClassifier.WIDGET_TYPE_NOTIFICATION) diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java index ebcaee87d6d8..dfa1ea0aac90 100644 --- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java +++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java @@ -330,7 +330,9 @@ public class SmartActionsHelperTest { List<TextClassifierEvent> events = argumentCaptor.getAllValues(); assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED); assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_SMART_ACTION); - assertThat(events.get(1).getScore()).isEqualTo(SCORE); + float[] scores = events.get(1).getScores(); + assertThat(scores).hasLength(1); + assertThat(scores[0]).isEqualTo(SCORE); } @Test diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index 5817118bc861..e0bb862c5362 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -37,6 +37,7 @@ android_library { "src/**/*.java", ":framework-networkstack-shared-srcs", ":services-networkstack-shared-srcs", + ":statslog-networkstack-java-gen", ], static_libs: [ "androidx.annotation_annotation", @@ -104,3 +105,11 @@ android_app { certificate: "networkstack", manifest: "AndroidManifest.xml", } + +genrule { + name: "statslog-networkstack-java-gen", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --java $(out) --module network_stack" + + " --javaPackage com.android.networkstack.metrics --javaClass NetworkStackStatsLog", + out: ["com/android/networkstack/metrics/NetworkStackStatsLog.java"], +} 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/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java index e7a607b1f921..822678717092 100644 --- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java +++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java @@ -95,8 +95,7 @@ public class NetworkStackUtils { * Look up the value of a property for a particular namespace from {@link DeviceConfig}. * @param namespace The namespace containing the property to look up. * @param name The name of the property to look up. - * @param defaultValue The value to return if the property does not exist or has no non-null - * value. + * @param defaultValue The value to return if the property does not exist or has no valid value. * @return the corresponding value, or defaultValue if none exists. */ @Nullable diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java index 225dc0f4bfdc..2523ecd4ea20 100644 --- a/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java +++ b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.metrics; +package com.android.networkstack.metrics; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java index e23f10f243dc..93089017fd47 100644 --- a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java +++ b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package android.net.metrics; +package com.android.networkstack.metrics; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.captiveportal.CaptivePortalProbeResult; import android.util.Log; -import android.util.StatsLog; import com.android.internal.util.HexDump; import com.android.server.connectivity.nano.DataStallEventProto; @@ -37,13 +36,11 @@ import com.android.server.connectivity.nano.DataStallEventProto; */ public class DataStallStatsUtils { private static final String TAG = DataStallStatsUtils.class.getSimpleName(); - private static final int DATA_STALL_EVENT_ID = 121; private static final boolean DBG = false; private static int probeResultToEnum(@Nullable final CaptivePortalProbeResult result) { if (result == null) return DataStallEventProto.INVALID; - // TODO: Add partial connectivity support. if (result.isSuccessful()) { return DataStallEventProto.VALID; } else if (result.isPortal()) { @@ -65,8 +62,7 @@ public class DataStallStatsUtils { Log.d(TAG, "write: " + stats + " with result: " + validationResult + ", dns: " + HexDump.toHexString(stats.mDns)); } - // TODO(b/124613085): Update API once the public StatsLog API is ready. - StatsLog.write(DATA_STALL_EVENT_ID, + NetworkStackStatsLog.write(NetworkStackStatsLog.DATA_STALL_EVENT, stats.mEvaluationType, validationResult, stats.mNetworkType, diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java index 6fb4b0d79a64..afe166ba9246 100644 --- a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java +++ b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java @@ -181,4 +181,9 @@ public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub @Override public void onStrictCleartextDetected(int uid, String hex) {} + + @Override + public int getInterfaceVersion() { + return INetdUnsolicitedEventListener.VERSION; + } } diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 588dcf2a83f5..27d420328017 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -65,8 +65,6 @@ import android.net.TrafficStats; import android.net.Uri; import android.net.captiveportal.CaptivePortalProbeResult; import android.net.captiveportal.CaptivePortalProbeSpec; -import android.net.metrics.DataStallDetectionStats; -import android.net.metrics.DataStallStatsUtils; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.metrics.ValidationProbeEvent; @@ -100,7 +98,10 @@ 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; import java.io.IOException; import java.net.HttpURLConnection; @@ -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/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index fa41284317bb..910bdc7e600f 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -59,8 +59,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.captiveportal.CaptivePortalProbeResult; -import android.net.metrics.DataStallDetectionStats; -import android.net.metrics.DataStallStatsUtils; import android.net.metrics.IpConnectivityLog; import android.net.util.SharedLog; import android.net.wifi.WifiInfo; @@ -78,6 +76,9 @@ import android.util.ArrayMap; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.networkstack.metrics.DataStallDetectionStats; +import com.android.networkstack.metrics.DataStallStatsUtils; + import org.junit.After; import org.junit.Before; import org.junit.Test; 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/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 19e800b70dab..80904b939cd3 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -293,9 +293,9 @@ <string name="show_touches" msgid="2642976305235070316">"Wys tikke"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Wys visuele terugvoer vir tikke"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Wys oppervlakopdaterings"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Flits vensteroppervlaktes in geheel wanneer dit opdateer"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Flits totale vensteroppervlakke wanneer dit opdateer"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Wys aansigopdaterings"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Flits aansigte binne vensters wanneer getrek word"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Flits aansigte binne vensters wanneer dit getrek word"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Wys hardewarelae se opdaterings"</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Laat hardewarelae groen flits wanneer hulle opgedateer word"</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"Ontfout GPU-oortrek"</string> @@ -314,7 +314,7 @@ <string name="show_non_rect_clip" msgid="505954950474595172">"Ontfout nie-reghoekige knipbedrywighede"</string> <string name="track_frame_time" msgid="6094365083096851167">"Profiel-HWUI-lewering"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Aktiveer GPU-ontfoutlae"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Laat laai van GPU-ontfoutlae vir ontfoutapps toe"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Laat laai van GPU-ontfoutlae vir ontfoutprogramme toe"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Vensteranimasieskaal"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Oorganganimasieskaal"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animator-tydsduurskaal"</string> @@ -355,7 +355,7 @@ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktief. Tik om te wissel."</string> <string name="standby_bucket_summary" msgid="6567835350910684727">"Programbystandstatus:<xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="8097287939865165213">"Lopende dienste"</string> - <string name="runningservices_settings_summary" msgid="854608995821032748">"Sien en beheer dienste wat tans loop"</string> + <string name="runningservices_settings_summary" msgid="854608995821032748">"Sien en beheer dienste wat tans aktief is"</string> <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string> <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stel WebView-implementering"</string> <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Hierdie keuse is nie meer geldig nie. Probeer weer."</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 2dec063ac444..7e1c6961462f 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -213,7 +213,7 @@ <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Dozvoli otključavanje funkcije za pokretanje"</string> <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"Želite li da dozvolite otključavanje proizvođača originalne opreme (OEM)?"</string> <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"UPOZORENJE: Funkcije za zaštitu uređaja neće funkcionisati na ovom uređaju dok je ovo podešavanje uključeno."</string> - <string name="mock_location_app" msgid="7966220972812881854">"Izaberi aplikaciju za lažnu lokaciju"</string> + <string name="mock_location_app" msgid="7966220972812881854">"Izaberite aplikaciju za lažnu lokaciju"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"Aplikacija za lažnu lokaciju nije podešena"</string> <string name="mock_location_app_set" msgid="8966420655295102685">"Aplikacija za lažnu lokaciju: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Umrežavanje"</string> @@ -289,7 +289,7 @@ <string name="strict_mode" msgid="1938795874357830695">"Omogućen je strogi režim"</string> <string name="strict_mode_summary" msgid="142834318897332338">"Neka ekran treperi kada aplikacije obavljaju duge operacije na glavnoj niti"</string> <string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string> - <string name="pointer_location_summary" msgid="840819275172753713">"Postav. element sa trenutnim podacima o dodiru"</string> + <string name="pointer_location_summary" msgid="840819275172753713">"Preklopni element sa trenutnim podacima o dodiru"</string> <string name="show_touches" msgid="2642976305235070316">"Prikazuj dodire"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Prikazuj vizuelne povratne informacije za dodire"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Prikaži ažuriranja površine"</string> @@ -311,8 +311,8 @@ <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smer rasporeda ekrana zdesna nalevo za sve lokalitete"</string> <string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string> <string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u OpenGL ES 2.0 aplikacijama"</string> - <string name="show_non_rect_clip" msgid="505954950474595172">"Otkloni greške u vezi sa radnjama za isecanje oblasti koje nisu pravougaonog oblika"</string> - <string name="track_frame_time" msgid="6094365083096851167">"Prik. prof. pomoću HWUI-a"</string> + <string name="show_non_rect_clip" msgid="505954950474595172">"Otkloni greške isecanja oblasti koje nisu pravougaonog oblika"</string> + <string name="track_frame_time" msgid="6094365083096851167">"Penderuj pomoću HWUI-a"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Omogući slojeve za otklanjanje grešaka GPU-a"</string> <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Omogući učitavanje otk. greš. GPU-a u apl. za otk. greš."</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Razmera animacije prozora"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index fedfbcb28d75..2de397c23850 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -342,7 +342,7 @@ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ідзе загрузка…"</string> <string-array name="color_mode_names"> <item msgid="2425514299220523812">"Сочны (па змаўчанні)"</item> - <item msgid="8446070607501413455">"Натуральны"</item> + <item msgid="8446070607501413455">"Натуральныя"</item> <item msgid="6553408765810699025">"Стандартны"</item> </string-array> <string-array name="color_mode_descriptions"> @@ -418,7 +418,7 @@ <item msgid="8934126114226089439">"50 %"</item> <item msgid="1286113608943010849">"100 %"</item> </string-array> - <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> таму назад"</string> + <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> таму"</string> <string name="remaining_length_format" msgid="7886337596669190587">"Засталося <xliff:g id="ID_1">%1$s</xliff:g>"</string> <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Маленькі"</string> <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Стандартны"</string> diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml index ce3ca16bbe56..a9f13bbab4b1 100644 --- a/packages/SettingsLib/res/values-bn/arrays.xml +++ b/packages/SettingsLib/res/values-bn/arrays.xml @@ -55,7 +55,7 @@ </string-array> <string-array name="hdcp_checking_summaries"> <item msgid="505558545611516707">"HDCP পরীক্ষণ কখনও ব্যবহার করবেন না"</item> - <item msgid="3878793616631049349">"শুধুমাত্র DRM সামগ্রীর জন্য HDCP চেক করা ব্যবহার করুন"</item> + <item msgid="3878793616631049349">"শুধুমাত্র \'DRM কন্টেন্টের জন্য HDCP চেক\' চালু করুন"</item> <item msgid="45075631231212732">"সর্বদা HDCP পরীক্ষণ ব্যবহার করুন"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 42223bdd3541..9c5f501a4fa4 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -152,7 +152,7 @@ <string name="launch_defaults_some" msgid="313159469856372621">"কিছু ডিফল্ট সেট করা রয়েছে"</string> <string name="launch_defaults_none" msgid="4241129108140034876">"কোনো ডিফল্ট সেট করা নেই"</string> <string name="tts_settings" msgid="8186971894801348327">"পাঠ্য থেকে ভাষ্য আউটপুট সেটিংস"</string> - <string name="tts_settings_title" msgid="1237820681016639683">"টেক্সট-থেকে-স্পীচ"</string> + <string name="tts_settings_title" msgid="1237820681016639683">"টেক্সট-টু-স্পিচ"</string> <string name="tts_default_rate_title" msgid="6030550998379310088">"কথা বলার হার"</string> <string name="tts_default_rate_summary" msgid="4061815292287182801">"যে গতিতে পাঠ্য উচ্চারিত হয়"</string> <string name="tts_default_pitch_title" msgid="6135942113172488671">"পিচ"</string> @@ -204,10 +204,10 @@ <string name="enable_adb_summary" msgid="4881186971746056635">"USB কানেক্ট থাকাকালীন ডিবাগ মোড"</string> <string name="clear_adb_keys" msgid="4038889221503122743">"USB ডিবাগিং অনুমতিগুলি প্রত্যাহার করুন"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"ত্রুটি প্রতিবেদনের শর্টকাট"</string> - <string name="bugreport_in_power_summary" msgid="1778455732762984579">"একটি ত্রুটি প্রতিবেদন গ্রহণের জন্য পাওয়ার মেনুতে একটি বোতাম দেখান"</string> + <string name="bugreport_in_power_summary" msgid="1778455732762984579">"সমস্যার তথ্য ক্যাপচার করতে পাওয়ার মেনুতে একটি বোতাম দেখান"</string> <string name="keep_screen_on" msgid="1146389631208760344">"জাগিয়ে রাখুন"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"চার্জ হওয়ার স্ক্রিন কখনই নিদ্রা মোডে যাবে না"</string> - <string name="bt_hci_snoop_log" msgid="3340699311158865670">"ব্লুটুথ HCI স্নুপ লগ সক্ষম করুন"</string> + <string name="bt_hci_snoop_log" msgid="3340699311158865670">"ব্লুটুথ HCI স্নুপ লগ চালু করুন"</string> <string name="bt_hci_snoop_log_summary" msgid="8857606786588106495">"ব্লুটুথ প্যাকেট ক্যাপচার করুন। (এই সেটিং পরিবর্তন করার পরে ব্লুটুথ চালু অথবা বন্ধ করুন)"</string> <string name="oem_unlock_enable" msgid="6040763321967327691">"OEM আনলক করা হচ্ছে"</string> <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"বুট-লোডার আনলক করার অনুমতি দিন"</string> @@ -257,7 +257,7 @@ <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"USB কনফিগারেশন বেছে নিন"</string> <string name="allow_mock_location" msgid="2787962564578664888">"নকল অবস্থানের অনুমতি দিন"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"মক অবস্থানগুলি মঞ্জুর করুন"</string> - <string name="debug_view_attributes" msgid="6485448367803310384">"অ্যাট্রিবিউট পরিদর্শন দেখা সক্ষম করুন"</string> + <string name="debug_view_attributes" msgid="6485448367803310384">"অ্যাট্রিবিউট ইন্সপেকশন দেখা চালু করুন"</string> <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ওয়াই-ফাই সক্রিয় থাকার সময়েও (দ্রুত নেটওয়ার্কে পাল্টানোর জন্য) সর্বদা মোবাইল ডেটা সক্রিয় রাখুন।"</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন উপলব্ধ থাকলে ব্যবহার করুন"</string> <string name="adb_warning_title" msgid="6234463310896563253">"USB ডিবাগিং মঞ্জুর করবেন?"</string> @@ -313,7 +313,7 @@ <string name="force_msaa_summary" msgid="9123553203895817537">"OpenGL ES 2.0 অ্যাপ্লিকেশানগুলির মধ্যে 4x MSAA সক্রিয় করুন"</string> <string name="show_non_rect_clip" msgid="505954950474595172">"অ-আয়তক্ষেত্রাকার ক্লিপ অ্যাক্টিভিটি ডিবাগ করুন"</string> <string name="track_frame_time" msgid="6094365083096851167">"প্রোফাইল HWUI রেন্ডারিং"</string> - <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ডিবাগ স্তর সক্ষম করুন"</string> + <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU ডিবাগ স্তর চালু করুন"</string> <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"ডিবাগ অ্যাপের জন্য GPU ডিবাগ স্তর লোড হতে দিন"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"উইন্ডো অ্যানিমেশন স্কেল"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"ট্র্যানজিশন অ্যানিমেশন স্কেল"</string> diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml index 96772b6a139b..4c56ce578dab 100644 --- a/packages/SettingsLib/res/values-bs/arrays.xml +++ b/packages/SettingsLib/res/values-bs/arrays.xml @@ -76,7 +76,7 @@ <item msgid="3422726142222090896">"avrcp16"</item> </string-array> <string-array name="bluetooth_a2dp_codec_titles"> - <item msgid="7065842274271279580">"Koristi odabir sistema (zadano)"</item> + <item msgid="7065842274271279580">"Korištenje odabira sistema (zadano)"</item> <item msgid="7539690996561263909">"SBC"</item> <item msgid="686685526567131661">"AAC"</item> <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item> @@ -86,7 +86,7 @@ <item msgid="3304843301758635896">"Onemogući opcionalne kodeke"</item> </string-array> <string-array name="bluetooth_a2dp_codec_summaries"> - <item msgid="5062108632402595000">"Koristi odabir sistema (zadano)"</item> + <item msgid="5062108632402595000">"Korištenje odabira sistema (zadano)"</item> <item msgid="6898329690939802290">"SBC"</item> <item msgid="6839647709301342559">"AAC"</item> <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item> @@ -96,38 +96,38 @@ <item msgid="741805482892725657">"Onemogući opcionalne kodeke"</item> </string-array> <string-array name="bluetooth_a2dp_codec_sample_rate_titles"> - <item msgid="3093023430402746802">"Koristi odabir sistema (zadano)"</item> + <item msgid="3093023430402746802">"Korištenje odabira sistema (zadano)"</item> <item msgid="8895532488906185219">"44,1 kHz"</item> <item msgid="2909915718994807056">"48,0 kHz"</item> <item msgid="3347287377354164611">"88,2 kHz"</item> <item msgid="1234212100239985373">"96,0 kHz"</item> </string-array> <string-array name="bluetooth_a2dp_codec_sample_rate_summaries"> - <item msgid="3214516120190965356">"Koristi odabir sistema (zadano)"</item> + <item msgid="3214516120190965356">"Korištenje odabira sistema (zadano)"</item> <item msgid="4482862757811638365">"44,1 kHz"</item> <item msgid="354495328188724404">"48,0 kHz"</item> <item msgid="7329816882213695083">"88,2 kHz"</item> <item msgid="6967397666254430476">"96,0 kHz"</item> </string-array> <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles"> - <item msgid="2684127272582591429">"Koristi odabir sistema (zadano)"</item> + <item msgid="2684127272582591429">"Korištenje odabira sistema (zadano)"</item> <item msgid="5618929009984956469">"16 bitova/uzorak"</item> <item msgid="3412640499234627248">"24 bitova/uzorak"</item> <item msgid="121583001492929387">"32 bitova/uzorak"</item> </string-array> <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries"> - <item msgid="1081159789834584363">"Koristi odabir sistema (zadano)"</item> + <item msgid="1081159789834584363">"Korištenje odabira sistema (zadano)"</item> <item msgid="4726688794884191540">"16 bitova/uzorak"</item> <item msgid="305344756485516870">"24 bitova/uzorak"</item> <item msgid="244568657919675099">"32 bitova/uzorak"</item> </string-array> <string-array name="bluetooth_a2dp_codec_channel_mode_titles"> - <item msgid="5226878858503393706">"Koristi odabir sistema (zadano)"</item> + <item msgid="5226878858503393706">"Korištenje odabira sistema (zadano)"</item> <item msgid="4106832974775067314">"Mono"</item> <item msgid="5571632958424639155">"Stereo"</item> </string-array> <string-array name="bluetooth_a2dp_codec_channel_mode_summaries"> - <item msgid="4118561796005528173">"Koristi odabir sistema (zadano)"</item> + <item msgid="4118561796005528173">"Korištenje odabira sistema (zadano)"</item> <item msgid="8900559293912978337">"Mono"</item> <item msgid="8883739882299884241">"Stereo"</item> </string-array> @@ -165,11 +165,11 @@ </string-array> <string-array name="select_logd_size_summaries"> <item msgid="6921048829791179331">"Isključeno"</item> - <item msgid="2969458029344750262">"64K po međumemoriji dnevnika"</item> - <item msgid="1342285115665698168">"256k po međumemoriji dnevnika"</item> - <item msgid="1314234299552254621">"1M po međumemoriji dnevnika"</item> - <item msgid="3606047780792894151">"4M po međumemoriji dnevnika"</item> - <item msgid="5431354956856655120">"16M po međumemoriji dnevnika"</item> + <item msgid="2969458029344750262">"64K po međumemoriji zapisnika"</item> + <item msgid="1342285115665698168">"256k po međumemoriji zapisnika"</item> + <item msgid="1314234299552254621">"1M po međumemoriji zapisnika"</item> + <item msgid="3606047780792894151">"4M po međumemoriji zapisnika"</item> + <item msgid="5431354956856655120">"16M po međumemoriji zapisnika"</item> </string-array> <string-array name="select_logpersist_titles"> <item msgid="1744840221860799971">"Isključeno"</item> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index cb34f1d45535..9868f1aafa4a 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -204,8 +204,8 @@ <string name="enable_adb_summary" msgid="4881186971746056635">"Način rada za uklanjanje grešaka kada je povezan USB"</string> <string name="clear_adb_keys" msgid="4038889221503122743">"Ukini odobrenja otklanjanja grešaka putem uređaja spojenog na USB"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"Prečica za izvještaj o greškama"</string> - <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Prikaži tipku za prijavu grešaka u izborniku za potrošnju energije"</string> - <string name="keep_screen_on" msgid="1146389631208760344">"Ostani aktivan"</string> + <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Prikaz dugmeta za prijavu grešaka u meniju napajanja"</string> + <string name="keep_screen_on" msgid="1146389631208760344">"Ne zaključavaj ekran"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"Ekran neće prelaziti u stanje mirovanja tokom punjenja"</string> <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Omogući Bluetooth HCI snoop zapis"</string> <string name="bt_hci_snoop_log_summary" msgid="8857606786588106495">"Snimite Bluetooth pakete. (Uključite/isključite Bluetooth nakon što promijenite ovu postavku)"</string> @@ -213,13 +213,13 @@ <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Dozvoli otključavanje bootloadera"</string> <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"Želite li dozvoliti OEM otključavanje?"</string> <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"UPOZORENJE: Funkcije zaštite ovog uređaja neće funkcionirati dok je ova postavka uključena."</string> - <string name="mock_location_app" msgid="7966220972812881854">"Odaberite aplikaciju za lažne lokacije"</string> + <string name="mock_location_app" msgid="7966220972812881854">"Odaberite aplikaciju za lažnu lokaciju"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"Aplikacija za lažnu lokaciju nije postavljena"</string> - <string name="mock_location_app_set" msgid="8966420655295102685">"Aplikacija za lažne lokacije: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="mock_location_app_set" msgid="8966420655295102685">"Aplikacija za lažnu lokaciju: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Umrežavanje"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certifikacija bežičnog prikaza"</string> - <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogući detaljniju evidenciju za WiFi"</string> - <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilna mreža za prijenos podataka je uvijek aktivna"</string> + <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogući detaljni zapisnik za WiFi"</string> + <string name="mobile_data_always_on" msgid="8774857027458200434">"Prijenos podataka na mobilnoj mreži je uvijek aktivan"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzavanje za povezivanje putem mobitela"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Prikaži Bluetooth uređaje bez naziva"</string> <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući apsolutnu jačinu zvuka"</string> @@ -243,12 +243,12 @@ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Naziv hosta pružaoca usluge privatnog DNS-a"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite naziv hosta pružaoca usluge DNS-a"</string> <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Povezivanje nije uspjelo"</string> - <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaži opcije za certifikaciju bežičnog prikaza"</string> - <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećava nivo evidentiranja za WiFi. Prikaz po SSID RSSI-ju u Biraču WiFi-ja"</string> + <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za certifikaciju bežičnog prikaza"</string> + <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećani nivo zapisnika za WiFi. Prikaz po SSID RSSI-ju u Biraču WiFi-ja"</string> <string name="wifi_metered_label" msgid="4514924227256839725">"S naplatom"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Mreža bez ograničenja prometa"</string> - <string name="select_logd_size_title" msgid="7433137108348553508">"Veličine bafera za zapisnik"</string> - <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Odaberite veličine za Logger prema međumemoriji evidencije"</string> + <string name="select_logd_size_title" msgid="7433137108348553508">"Veličine međumemorije zapisnika"</string> + <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Odaberite veličinu međumemorije zapisnika"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Želite li obrisati trajnu pohranu zapisivača?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Kada više ne pratimo trajnog zapisivača, trebamo u potpunosti izbrisati podatke zapisivača na vašem uređaju."</string> <string name="select_logpersist_title" msgid="7530031344550073166">"Pohrani podatke zapisivača na uređaju"</string> @@ -258,23 +258,23 @@ <string name="allow_mock_location" msgid="2787962564578664888">"Dozvoli lažne lokacije"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Dozvoli lažne lokacije"</string> <string name="debug_view_attributes" msgid="6485448367803310384">"Omogući pregled atributa prikaza"</string> - <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Uvijek drži prijenos podataka na mobilnoj mreži aktivnim, čak i kada je WiFi aktivan (za brzo prebacivanje između mreža)."</string> - <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Koristi hardversko ubrzavanje dijeljenja veze, ako je dostupno"</string> + <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Prijenos podataka na mobilnoj mreži ostaje aktivan čak i kada je aktiviran WiFi (za brzo prebacivanje između mreža)."</string> + <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Korištenje hardverskog ubrzavanja za povezivanje putem mobitela ako je dostupno"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Omogućiti otklanjanje grešaka putem uređaja spojenog na USB?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"Otklanjanje grešaka putem uređaja spojenog na USB je namijenjeno samo u svrhe razvoja aplikacija. Koristite ga za kopiranje podataka između računara i uređaja, instaliranje aplikacija na uređaj bez obavještenja te čitanje podataka iz zapisnika."</string> <string name="adb_keys_warning_message" msgid="5659849457135841625">"Opozvati pristup otklanjanju grešaka putem uređaja spojenog na USB za sve računare koje ste prethodno ovlastili?"</string> <string name="dev_settings_warning_title" msgid="7244607768088540165">"Dopustiti postavke za razvoj?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Ove postavke su namijenjene samo za svrhe razvoja. Mogu izazvati pogrešno ponašanje uređaja i aplikacija na njemu."</string> - <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificiraj aplikacije putem USB-a"</string> + <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Potvrdi aplikacije putem USB-a"</string> <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerava da li se u aplikacijama instaliranim putem ADB-a/ADT-a javlja zlonamjerno ponašanje."</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Prikazat će se Bluetooth uređaji bez naziva (samo MAC adrese)"</string> - <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava opciju Bluetooth apsolutne jačine zvuka u slučaju problema s jačinom zvuka na udaljenim uređajima, kao što je neprihvatljivo glasan zvuk ili nedostatak kontrole."</string> + <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava funkciju apsolutne jačine zvuka za Bluetooth u slučaju problema s jačinom zvuka na udaljenim uređajima, kao što je neprihvatljivo glasan zvuk ili nedostatak kontrole."</string> <string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string> <string name="enable_terminal_summary" msgid="67667852659359206">"Omogući terminalnu aplik. koja nudi pristup lok. kom. okruženju"</string> - <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjeravanje"</string> + <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjera"</string> <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"Postavke HDCP provjere"</string> <string name="debug_debugging_category" msgid="6781250159513471316">"Otklanjanje grešaka"</string> - <string name="debug_app" msgid="8349591734751384446">"Odaberi aplikaciju za otklanjanje grešaka"</string> + <string name="debug_app" msgid="8349591734751384446">"Odabir aplikacije za otklanjanje grešaka"</string> <string name="debug_app_not_set" msgid="718752499586403499">"Nema postavljenih aplikac. za otklanjanje grešaka"</string> <string name="debug_app_set" msgid="2063077997870280017">"Aplikacija za otklanjanje grešaka: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="select_application" msgid="5156029161289091703">"Odaberite aplikaciju"</string> @@ -283,57 +283,57 @@ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacija u kojoj se otklanjaju greške čeka da se priloži program za otklanjanje grešaka prije izvršavanja"</string> <string name="debug_input_category" msgid="1811069939601180246">"Ulaz"</string> <string name="debug_drawing_category" msgid="6755716469267367852">"Crtanje"</string> - <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Prikaz s hardverskom akceleracijom"</string> + <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardverski ubrzano prikazivanje"</string> <string name="media_category" msgid="4388305075496848353">"Mediji"</string> <string name="debug_monitoring_category" msgid="7640508148375798343">"Praćenje"</string> - <string name="strict_mode" msgid="1938795874357830695">"Omogućen strogi način rada"</string> - <string name="strict_mode_summary" msgid="142834318897332338">"Prikaži ekran uz treptanje kada aplikacije vrše duge operacije u glavnoj niti"</string> + <string name="strict_mode" msgid="1938795874357830695">"Omogući strogi način rada"</string> + <string name="strict_mode_summary" msgid="142834318897332338">"Ekran bljeska kada aplikacije vrše duge operacije u glavnoj niti"</string> <string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string> - <string name="pointer_location_summary" msgid="840819275172753713">"Trenutni podaci o dodirivanju prikazuju se u nadsloju preko ekrana"</string> - <string name="show_touches" msgid="2642976305235070316">"Prikaži dodirivanja"</string> - <string name="show_touches_summary" msgid="6101183132903926324">"Prikaži vizuelne povratne informacije za dodirivanja"</string> + <string name="pointer_location_summary" msgid="840819275172753713">"Preklapanje ekrana s trenutnim podacima o dodiru"</string> + <string name="show_touches" msgid="2642976305235070316">"Prikaži dodire"</string> + <string name="show_touches_summary" msgid="6101183132903926324">"Prikaz vizuelnih povratnih informacija za dodire"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Prikaži ažuriranja za površinu"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Prikaži cijele površine prozora uz treptanje prilikom ažuriranja"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Osvjetljava sve površine prozora kada se ažuriraju"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Prikaži ažuriranja prikaza"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Zatreperi prikaze u prozorima prilikom iscrtavanja"</string> - <string name="show_hw_layers_updates" msgid="5645728765605699821">"Prikaži dodatne informacije za ažuriranja za hardver"</string> - <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Hardverski slojevi trepću zelenom bojom pri ažuriranju"</string> - <string name="debug_hw_overdraw" msgid="2968692419951565417">"Otkl. greške GPU preklap."</string> - <string name="disable_overlays" msgid="2074488440505934665">"Onemog. HW preklapanja"</string> - <string name="disable_overlays_summary" msgid="3578941133710758592">"Uvijek koristi GPU za kompoziciju ekrana"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Osvjetljava prikaze u prozorima prilikom iscrtavanja"</string> + <string name="show_hw_layers_updates" msgid="5645728765605699821">"Prikaži ažuriranja hardverskih slojeva"</string> + <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Hardverski slojevi trepere zeleno pri ažuriranju"</string> + <string name="debug_hw_overdraw" msgid="2968692419951565417">"Otkl. greške GPU preklapanja"</string> + <string name="disable_overlays" msgid="2074488440505934665">"Onemog. hardverska prekl."</string> + <string name="disable_overlays_summary" msgid="3578941133710758592">"Uvijek se koristi GPU za slaganje ekrana"</string> <string name="simulate_color_space" msgid="6745847141353345872">"Simuliraj prostor boje"</string> <string name="enable_opengl_traces_title" msgid="6790444011053219871">"Omogući OpenGL zapise"</string> - <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Isključi USB audio usmjeravanje"</string> - <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Onemogući autom. usmjerav. na USB audio periferije"</string> + <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Onemogući USB preusmjer. zvuka"</string> + <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Onemoguć. autom. preusmj. na USB audio perif. uređ."</string> <string name="debug_layout" msgid="5981361776594526155">"Prikaži granice rasporeda"</string> - <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice isječka, margine itd."</string> + <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaz granica isječka, margina itd."</string> <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Prisilno postavi raspored s desna ulijevo"</string> - <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Prisilno postavi raspored ekrana s desna ulijevo za sve regije"</string> + <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Prisilno postavljanje rasporeda ekrana s desna ulijevo za sve regije"</string> <string name="force_msaa" msgid="7920323238677284387">"Prinudno primijeni 4x MSAA"</string> - <string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u OpenGL ES 2.0 aplikacijama"</string> - <string name="show_non_rect_clip" msgid="505954950474595172">"Ispravi greške na nepravougaonim operacijama isjecanja"</string> + <string name="force_msaa_summary" msgid="9123553203895817537">"Omogućava 4x MSAA u OpenGL ES 2.0 aplikacijama"</string> + <string name="show_non_rect_clip" msgid="505954950474595172">"Otkl. greške na operac. nepravoug. isjecanja"</string> <string name="track_frame_time" msgid="6094365083096851167">"Profil HWUI iscrtavanja"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Omogući slojeve za otklanjanje grešaka na GPU-u"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Omogući učitavanje slojeva za otklanjanje grešaka na GPU-u za aplikacije za otklanjanje grešaka"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Omoguć. učit. sloj. za otkl. greš. na GPU-u za apl. za otkl. greš."</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Skala animacije prozora"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Skala animacije prijelaza"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Skala trajanja animatora"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simuliraj sekundarne ekrane"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Aplikacije"</string> <string name="immediately_destroy_activities" msgid="1579659389568133959">"Ne čuvaj aktivnosti"</string> - <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Obustavi svaku aktivnost čim je korisnik napusti"</string> + <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Obustavlja se svaka aktivnost čim je korisnik napusti"</string> <string name="app_process_limit_title" msgid="4280600650253107163">"Ograničenje procesa u pozadini"</string> <string name="show_all_anrs" msgid="4924885492787069007">"Prikaži ANR-e u pozadini"</string> - <string name="show_all_anrs_summary" msgid="6636514318275139826">"Prikaži dijalog \"Aplikacija ne reagira\" za aplikacije pokrenute u pozadini"</string> - <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Prikaz upozorenja na obavještenju o kanalu"</string> - <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Prikaz upozorenja na ekranu kada aplikacija pošalje obavještenje bez važećeg kanala."</string> + <string name="show_all_anrs_summary" msgid="6636514318275139826">"Prikaz dijaloga \"Aplikacija ne reagira\" za aplikacije pokrenute u pozadini"</string> + <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Prikaži upozorenja kanala obavještenja"</string> + <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Prikaz upozorenja na ekranu kada aplikacija pošalje obavještenje bez važećeg kanala"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Nametni aplikacije na vanjskoj pohrani"</string> <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Omogućava upisivanje svih aplikacija u vanjsku pohranu, bez obzira na prikazane vrijednosti"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni aktivnostima mijenjanje veličina"</string> - <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući mijenjanje veličine svih aktivnosti za prikaz s više prozora, bez obzira na prikazane vrijednosti."</string> + <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogućava mijenjanje veličine svih aktivnosti za prikaz s više prozora, bez obzira na prikazane vrijednosti."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore nepravilnih oblika"</string> - <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogući podršku za eksperimentalne prozore nepravilnih oblika."</string> - <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka za sigurnosnu kopiju radne površine"</string> + <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogućava podršku za eksperimentalne prozore nepravilnih oblika."</string> + <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka sigurnosne kopije za računar"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string> <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije s radne površine"</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za sigurnosnu kopiju je postavljena"</string> @@ -431,7 +431,7 @@ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Naprijed"</string> <string name="retail_demo_reset_title" msgid="696589204029930100">"Potrebna je lozinka"</string> <string name="active_input_method_subtypes" msgid="3596398805424733238">"Aktivne metode unosa"</string> - <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Koristi jezik sistema"</string> + <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Koristite jezik sistema"</string> <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Otvaranje postavki za <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> nije uspjelo"</string> <string name="ime_security_warning" msgid="4135828934735934248">"Ovaj način unosa može prikupiti sav tekst koji upišete, uključujući lične podatke kao što su lozinke i brojevi kreditnih kartica. Način omogućava aplikacija <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Da li želite koristiti ovaj način unosa?"</string> <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"Napomena: Nakon ponovnog pokretanja, ova aplikacija se neće moći pokrenuti dok ne otključate telefon"</string> diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml index 33385e4e0587..15100bfddd1b 100644 --- a/packages/SettingsLib/res/values-ca/arrays.xml +++ b/packages/SettingsLib/res/values-ca/arrays.xml @@ -165,11 +165,11 @@ </string-array> <string-array name="select_logd_size_summaries"> <item msgid="6921048829791179331">"No"</item> - <item msgid="2969458029344750262">"64 K / memòria intermèdia reg."</item> - <item msgid="1342285115665698168">"256 K / memòria intermèdia reg."</item> + <item msgid="2969458029344750262">"64 K / memòria intermèdia del registre"</item> + <item msgid="1342285115665698168">"256 K / memòria intermèdia del registre"</item> <item msgid="1314234299552254621">"1 M / memòria intermèdia reg."</item> - <item msgid="3606047780792894151">"4 M / memòria intermèdia reg."</item> - <item msgid="5431354956856655120">"16 M / memòria intermèdia reg."</item> + <item msgid="3606047780792894151">"4 M / memòria intermèdia del registre"</item> + <item msgid="5431354956856655120">"16 M / memòria intermèdia del registre"</item> </string-array> <string-array name="select_logpersist_titles"> <item msgid="1744840221860799971">"Desactivat"</item> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 5a9ec706fe9e..1ddd562e1af2 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -151,9 +151,9 @@ <string name="running_process_item_user_label" msgid="3129887865552025943">"Usuari: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string> <string name="launch_defaults_some" msgid="313159469856372621">"S\'han definit alguns valors predeterminats"</string> <string name="launch_defaults_none" msgid="4241129108140034876">"No s\'ha definit cap valor predeterminat"</string> - <string name="tts_settings" msgid="8186971894801348327">"Configuració de text a veu"</string> - <string name="tts_settings_title" msgid="1237820681016639683">"Sortida de text a veu"</string> - <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocitat de veu"</string> + <string name="tts_settings" msgid="8186971894801348327">"Configuració de text a parla"</string> + <string name="tts_settings_title" msgid="1237820681016639683">"Sortida de text a parla"</string> + <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocitat de parla"</string> <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocitat de lectura del text"</string> <string name="tts_default_pitch_title" msgid="6135942113172488671">"To"</string> <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta el to de la veu sintetitzada"</string> @@ -165,8 +165,8 @@ <string name="tts_play_example_summary" msgid="8029071615047894486">"Reprodueix una breu demostració de síntesi de veu"</string> <string name="tts_install_data_title" msgid="4264378440508149986">"Instal·la dades de veu"</string> <string name="tts_install_data_summary" msgid="5742135732511822589">"Instal·la les dades de veu necessàries per a la síntesi de veu"</string> - <string name="tts_engine_security_warning" msgid="8786238102020223650">"Pot ser que aquest motor de síntesi de la parla pugui recopilar tot el text que es dirà en veu alta, incloses les dades personals, com ara les contrasenyes i els números de les targetes de crèdit. Ve del motor <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Vols activar l\'ús d\'aquest motor de síntesi de la parla?"</string> - <string name="tts_engine_network_required" msgid="1190837151485314743">"Aquest idioma requereix una connexió de xarxa activa per a la sortida de text a veu."</string> + <string name="tts_engine_security_warning" msgid="8786238102020223650">"Pot ser que aquest motor de síntesi de parla pugui recopilar tot el text que s\'enunciarà, incloses les dades personals, com ara les contrasenyes i els números de les targetes de crèdit. Ve del motor <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Vols activar l\'ús d\'aquest motor de síntesi de parla?"</string> + <string name="tts_engine_network_required" msgid="1190837151485314743">"Aquest idioma requereix una connexió de xarxa activa per a la sortida de text a parla."</string> <string name="tts_default_sample_string" msgid="4040835213373086322">"Això és un exemple de síntesi de veu"</string> <string name="tts_status_title" msgid="7268566550242584413">"Estat de l\'idioma predeterminat"</string> <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> és totalment compatible"</string> @@ -175,7 +175,7 @@ <string name="tts_status_checking" msgid="5339150797940483592">"S\'està comprovant…"</string> <string name="tts_engine_settings_title" msgid="3499112142425680334">"Configuració de: <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string> <string name="tts_engine_settings_button" msgid="1030512042040722285">"Obre la configuració del motor"</string> - <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Motor preferit"</string> + <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Motor preferent"</string> <string name="tts_general_section_title" msgid="4402572014604490502">"General"</string> <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Restableix el to de la veu"</string> <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Restableix el to predeterminat amb què es llegeix el text."</string> @@ -201,21 +201,21 @@ <string name="tethering_settings_not_available" msgid="6765770438438291012">"La configuració de compartició de xarxa no està disponible per a aquest usuari."</string> <string name="apn_settings_not_available" msgid="7873729032165324000">"La configuració del nom del punt d\'accés no està disponible per a aquest usuari."</string> <string name="enable_adb" msgid="7982306934419797485">"Depuració per USB"</string> - <string name="enable_adb_summary" msgid="4881186971746056635">"Activa el mode de depuració quan el dispositiu estigui connectat per USB"</string> + <string name="enable_adb_summary" msgid="4881186971746056635">"Mode de depuració quan l\'USB està connectat"</string> <string name="clear_adb_keys" msgid="4038889221503122743">"Revoca autoritzacions de depuració per USB"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"Drecera per a informe d\'errors"</string> <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostra un botó al menú d\'engegada per crear un informe d\'errors"</string> <string name="keep_screen_on" msgid="1146389631208760344">"Pantalla sempre activa"</string> - <string name="keep_screen_on_summary" msgid="2173114350754293009">"La pantalla no entra mai en mode de repòs si el dispositiu està carregant-se"</string> + <string name="keep_screen_on_summary" msgid="2173114350754293009">"La pantalla no entra mai en mode de repòs si el dispositiu s\'està carregant"</string> <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Activa registre de Bluetooth HCI"</string> <string name="bt_hci_snoop_log_summary" msgid="8857606786588106495">"Captura els paquets de Bluetooth. Activa el Bluetooth un cop hagis canviat aquesta opció."</string> <string name="oem_unlock_enable" msgid="6040763321967327691">"Desbloqueig d\'OEM"</string> <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Permet desbloquejar el bootloader"</string> <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"Permetre el desbloqueig d\'OEM?"</string> <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"ADVERTIMENT: les funcions de protecció del dispositiu no funcionaran mentre aquesta opció estigui activada."</string> - <string name="mock_location_app" msgid="7966220972812881854">"Selecciona aplicació per simular ubicació"</string> - <string name="mock_location_app_not_set" msgid="809543285495344223">"No s\'ha definit cap aplicació per simular ubicació"</string> - <string name="mock_location_app_set" msgid="8966420655295102685">"Aplicació per simular ubicació: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="mock_location_app" msgid="7966220972812881854">"Selecciona una aplicació d\'ubicació simulada"</string> + <string name="mock_location_app_not_set" msgid="809543285495344223">"No s\'ha definit cap aplicació d\'ubicació simulada"</string> + <string name="mock_location_app_set" msgid="8966420655295102685">"Aplicació d\'ubicació simulada: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Xarxes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificació de pantalla sense fil"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Activa el registre Wi‑Fi detallat"</string> @@ -244,37 +244,37 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introdueix el nom d\'amfitrió del proveïdor de DNS"</string> <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"No s\'ha pogut connectar"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra les opcions per a la certificació de pantalla sense fil"</string> - <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Augmenta nivell de registre Wi‑Fi i mostra\'l per SSID RSSI al Selector de Wi‑Fi"</string> + <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Augmenta nivell de registre Wi‑Fi, mostra\'l per SSID RSSI al selector de Wi‑Fi"</string> <string name="wifi_metered_label" msgid="4514924227256839725">"Amb límit de dades"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Sense límit de dades"</string> - <string name="select_logd_size_title" msgid="7433137108348553508">"Mides memòria intermèdia registrador"</string> - <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Mida Logger per memòria intermèdia"</string> + <string name="select_logd_size_title" msgid="7433137108348553508">"Mides de la mem. intermèdia del registrador"</string> + <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Selecciona la mida de la memòria intermèdia del registre"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Vols esborrar l\'emmagatzematge persistent del registrador?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Quan deixem de supervisar amb el registrador persistent, hem d\'esborrar les dades del registrador que hi ha al teu dispositiu."</string> - <string name="select_logpersist_title" msgid="7530031344550073166">"Desa dades reg. de manera permanent"</string> + <string name="select_logpersist_title" msgid="7530031344550073166">"Desa dades del registrador de manera permanent al dispositiu"</string> <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Selecciona memòries interm. de registre per emmag. de manera persistent al disp."</string> <string name="select_usb_configuration_title" msgid="2649938511506971843">"Selecciona configuració d\'USB"</string> <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Selecciona configuració d\'USB"</string> <string name="allow_mock_location" msgid="2787962564578664888">"Ubicacions simulades"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Permet les ubicacions simulades"</string> - <string name="debug_view_attributes" msgid="6485448367803310384">"Inspecció d\'atributs de visualització"</string> + <string name="debug_view_attributes" msgid="6485448367803310384">"Activa la inspecció d\'atributs de visualització"</string> <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantén les dades mòbils sempre actives, fins i tot quan la Wi‑Fi està activada (per canviar de xarxa ràpidament)."</string> - <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Fes servir l\'acceleració per maquinari per compartir la xarxa, si està disponible"</string> + <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Fes servir l\'acceleració per maquinari per a compartició de xarxa, si està disponible"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Voleu permetre la depuració per USB?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"La depuració per USB només està indicada per a activitats de desenvolupament. Fes-la servir intercanviar dades entre l\'ordinador i el dispositiu, per instal·lar aplicacions al dispositiu sense rebre notificacions i per llegir dades de registre."</string> <string name="adb_keys_warning_message" msgid="5659849457135841625">"Vols revocar l\'accés a la depuració per USB dels ordinadors que has autoritzat anteriorment?"</string> <string name="dev_settings_warning_title" msgid="7244607768088540165">"Vols permetre la conf. de desenvolupament?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Aquesta configuració només està prevista per a usos de desenvolupament. Pot fer que el dispositiu i que les aplicacions s\'interrompin o tinguin un comportament inadequat."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica aplicacions per USB"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprova les aplicacions instal·lades mitjançant ADB/ADT per detectar possibles comportaments perillosos"</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprova les aplicacions instal·lades mitjançant ADB/ADT per detectar comportaments perillosos"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Es mostraran els dispositius Bluetooth sense el nom (només l\'adreça MAC)"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva la funció de volum absolut del Bluetooth en cas que es produeixin problemes de volum amb dispositius remots, com ara un volum massa alt o una manca de control."</string> <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string> <string name="enable_terminal_summary" msgid="67667852659359206">"Activa l\'aplicació de terminal que ofereix accés al shell local"</string> - <string name="hdcp_checking_title" msgid="8605478913544273282">"Comprovació HDCP"</string> + <string name="hdcp_checking_title" msgid="8605478913544273282">"Comprovació d\'HDCP"</string> <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"Defineix comprovació HDCP"</string> <string name="debug_debugging_category" msgid="6781250159513471316">"Depuració"</string> - <string name="debug_app" msgid="8349591734751384446">"Aplicació per depurar"</string> + <string name="debug_app" msgid="8349591734751384446">"Selecciona una aplicació de depuració"</string> <string name="debug_app_not_set" msgid="718752499586403499">"No s\'ha definit cap aplicació de depuració"</string> <string name="debug_app_set" msgid="2063077997870280017">"Aplicació per depurar: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="select_application" msgid="5156029161289091703">"Selecciona una aplicació"</string> @@ -305,7 +305,7 @@ <string name="enable_opengl_traces_title" msgid="6790444011053219871">"Activa traces d\'OpenGL"</string> <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Desactiva l\'encaminament d\'àudio per USB"</string> <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Desactiva l\'encaminament automàtic als perifèrics d\'àudio USB"</string> - <string name="debug_layout" msgid="5981361776594526155">"Mostra límits de disseny"</string> + <string name="debug_layout" msgid="5981361776594526155">"Mostra límits de disposició"</string> <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra els límits de clips, els marges, etc."</string> <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Força direcció dreta-esquerra"</string> <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Força direcció de pantalla dreta-esquerra en totes les llengües"</string> @@ -314,7 +314,7 @@ <string name="show_non_rect_clip" msgid="505954950474595172">"Depura operacions de retall no rectangulars"</string> <string name="track_frame_time" msgid="6094365083096851167">"Renderització perfil HWUI"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activa les capes de depuració de GPU"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permet carregar capes de depuració de GPU per a apps de depuració"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permet capes de depuració de GPU en apps de depuració"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala d\'animació finestra"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala d\'animació transició"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de durada d\'animació"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 2f8a2b228885..71619e67f366 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -202,8 +202,8 @@ <string name="apn_settings_not_available" msgid="7873729032165324000">"Indstillingerne for Adgangspunkt (APN) er ikke tilgængelige for denne bruger"</string> <string name="enable_adb" msgid="7982306934419797485">"USB-fejlretning"</string> <string name="enable_adb_summary" msgid="4881186971746056635">"Fejlretningstilstand, når USB er tilsluttet"</string> - <string name="clear_adb_keys" msgid="4038889221503122743">"Tilbagekald tilladelser for USB-fejlfinding"</string> - <string name="bugreport_in_power" msgid="7923901846375587241">"Genvej til fejlrapporting"</string> + <string name="clear_adb_keys" msgid="4038889221503122743">"Tilbagekald tilladelser for USB-fejlretning"</string> + <string name="bugreport_in_power" msgid="7923901846375587241">"Genvej til fejlrapportering"</string> <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Vis en knap til oprettelse af fejlrapporter i afbrydermenuen"</string> <string name="keep_screen_on" msgid="1146389631208760344">"Lås ikke"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"Skærmen går ikke i dvale under opladning"</string> @@ -333,8 +333,8 @@ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tillad, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivér vinduer i frit format"</string> <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivér understøttelse af eksperimentelle vinduer i frit format."</string> - <string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal sikkerhedskopi"</string> - <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale fuldstændige sikkerhedskopieringer er i øjeblikket ikke beskyttet"</string> + <string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal backup"</string> + <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale komplette backups er i øjeblikket ikke beskyttet"</string> <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal backup"</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"Ny adgangskode til sikkerhedskopi er angivet"</string> <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ny adgangskode og bekræftelse matcher ikke"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 869245a50acc..63387ad0cdd8 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -152,7 +152,7 @@ <string name="launch_defaults_some" msgid="313159469856372621">"Einige Standardeinstellungen festgelegt"</string> <string name="launch_defaults_none" msgid="4241129108140034876">"Keine Standardeinstellungen festgelegt"</string> <string name="tts_settings" msgid="8186971894801348327">"Sprachausgabe"</string> - <string name="tts_settings_title" msgid="1237820681016639683">"Sprachausgabe-Ausgabe"</string> + <string name="tts_settings_title" msgid="1237820681016639683">"Sprachausgabe-Einstellungen"</string> <string name="tts_default_rate_title" msgid="6030550998379310088">"Sprechgeschwindigkeit"</string> <string name="tts_default_rate_summary" msgid="4061815292287182801">"Geschwindigkeit, mit der der Text gesprochen wird"</string> <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonlage"</string> @@ -166,7 +166,7 @@ <string name="tts_install_data_title" msgid="4264378440508149986">"Sprachdaten installieren"</string> <string name="tts_install_data_summary" msgid="5742135732511822589">"Sprachdaten für Sprachsynthese installieren"</string> <string name="tts_engine_security_warning" msgid="8786238102020223650">"Dieses Sprachsynthesemodul kann den gesamten gesprochenen Text erfassen, einschließlich personenbezogener Daten wie Passwörter und Kreditkartennummern. Es ist Teil der App \"<xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>\". Möchtest du dieses Sprachsynthesemodul aktivieren?"</string> - <string name="tts_engine_network_required" msgid="1190837151485314743">"Für diese Sprache ist zur Sprachausgabe-Ausgabe eine aktive Netzwerkverbindung erforderlich."</string> + <string name="tts_engine_network_required" msgid="1190837151485314743">"Die Sprachausgabe für diese Sprache ist nur bei einer aktiven Netzwerkverbindung möglich."</string> <string name="tts_default_sample_string" msgid="4040835213373086322">"Dies ist ein Beispiel für Sprachsynthese."</string> <string name="tts_status_title" msgid="7268566550242584413">"Status der Standardsprache"</string> <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> wird vollständig unterstützt."</string> @@ -204,7 +204,7 @@ <string name="enable_adb_summary" msgid="4881186971746056635">"Debugmodus bei Anschluss über USB"</string> <string name="clear_adb_keys" msgid="4038889221503122743">"USB-Debugging-Autorisierungen aufheben"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"Verknüpfung zu Fehlerbericht"</string> - <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Schaltfläche zum Abrufen von Fehlerberichten im Menü \"Ein/Aus\" anzeigen"</string> + <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Im Menü \"Ein/Aus\" wird eine Option zum Erstellen eines Fehlerberichts angezeigt"</string> <string name="keep_screen_on" msgid="1146389631208760344">"Aktiv lassen"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"Display wird beim Laden nie in den Ruhezustand versetzt"</string> <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Bluetooth HCI-Snoop-Protokoll aktivieren"</string> @@ -217,12 +217,12 @@ <string name="mock_location_app_not_set" msgid="809543285495344223">"Keine App für simulierte Standorte eingerichtet"</string> <string name="mock_location_app_set" msgid="8966420655295102685">"App für simulierte Standorte: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Netzwerke"</string> - <string name="wifi_display_certification" msgid="8611569543791307533">"Kabellose Übertragung"</string> - <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ausführliche WLAN-Protokolle aktivieren"</string> + <string name="wifi_display_certification" msgid="8611569543791307533">"Zertifizierung für kabellose Übertragung"</string> + <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ausführliche WLAN-Protokollierung aktivieren"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile Datennutzung immer aktiviert"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwarebeschleunigung für Tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth-Geräte ohne Namen anzeigen"</string> - <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Maximallautstärke deaktivieren"</string> + <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absolute Lautstärkeregelung deaktivieren"</string> <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-Version"</string> <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP-Version auswählen"</string> <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-Audio-Codec"</string> @@ -231,10 +231,10 @@ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="8010380028880963535">"Bluetooth-Audio-Codec auslösen\nAuswahl: Abtastrate"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth-Audio/Bits pro Sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="8063859754619484760">"Bluetooth-Audio-Codec auslösen\nAuswahl: Bits pro Sample"</string> - <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modus des Bluetooth-Audiokanals"</string> + <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth-Audiokanal-Modus"</string> <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="7234956835280563341">"Bluetooth-Audio-Codec auslösen\nAuswahl: Kanalmodus"</string> <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth-Audio-LDAC-Codec: Wiedergabequalität"</string> - <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="6893955536658137179">"Bluetooth-Audio-LDAC-Codec-\nAuswahl auslösen: Wiedergabequalität"</string> + <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="6893955536658137179">"Bluetooth-Audio-LDAC-Codec auslösen\nAuswahl: Wiedergabequalität"</string> <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privates DNS"</string> <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Privaten DNS-Modus auswählen"</string> @@ -251,7 +251,7 @@ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Größe pro Protokollpuffer wählen"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Speicher der dauerhaften Protokollierung löschen?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Wenn keine Überwachung über eine dauerhafte Protokollierung mehr stattfindet, sind wir dazu verpflichtet, die Protokolldaten auf deinem Gerät zu löschen."</string> - <string name="select_logpersist_title" msgid="7530031344550073166">"Protokolldaten dauerhaft speichern"</string> + <string name="select_logpersist_title" msgid="7530031344550073166">"Logger-Daten dauerhaft auf Gerät speichern"</string> <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Protokollzwischenspeicher zum dauerhaften Speichern auf Gerät auswählen"</string> <string name="select_usb_configuration_title" msgid="2649938511506971843">"USB-Konfiguration auswählen"</string> <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"USB-Konfiguration auswählen"</string> @@ -265,10 +265,10 @@ <string name="adb_keys_warning_message" msgid="5659849457135841625">"Zugriff auf USB-Debugging für alle zuvor autorisierten Computer aufheben?"</string> <string name="dev_settings_warning_title" msgid="7244607768088540165">"Entwicklungseinstellungen zulassen?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Diese Einstellungen sind ausschließlich für Entwicklungszwecke gedacht. Sie können dein Gerät und die darauf installierten Apps beschädigen oder zu unerwünschtem Verhalten führen."</string> - <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps über USB bestätigen"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Überprüft installierte Apps über ADB/ADT auf schädliches Verhalten"</string> - <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-Geräte ohne Namen (nur MAC-Adressen) werden angezeigt"</string> - <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiviert die Bluetooth-Maximallautstärkefunktion, falls auf Remote-Geräten Probleme mit der Lautstärke auftreten, wie beispielsweise übermäßig laute Wiedergabe oder fehlende Kontrolle bei der Steuerung."</string> + <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Über USB installierte Apps prüfen"</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Über ADB/ADT installierte Apps werden auf schädliches Verhalten geprüft"</string> + <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Bluetooth-Geräte werden ohne Namen und nur mit ihren MAC-Adressen angezeigt"</string> + <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiviert die Funktion \"Absolute Lautstärkeregelung\" für Bluetooth-Geräte, falls auf Remote-Geräten Probleme mit der Lautstärke auftreten, wie beispielsweise übermäßig laute Wiedergabe oder fehlende Steuerungsmöglichkeiten."</string> <string name="enable_terminal_title" msgid="95572094356054120">"Lokales Terminal"</string> <string name="enable_terminal_summary" msgid="67667852659359206">"Terminal-App mit Zugriff auf lokale Shell aktivieren"</string> <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-Prüfung"</string> @@ -282,59 +282,59 @@ <string name="wait_for_debugger" msgid="1202370874528893091">"Auf Debugger warten"</string> <string name="wait_for_debugger_summary" msgid="1766918303462746804">"App wartet vor der Ausführung auf den Start des Debuggers"</string> <string name="debug_input_category" msgid="1811069939601180246">"Eingabe"</string> - <string name="debug_drawing_category" msgid="6755716469267367852">"Zeichnung"</string> + <string name="debug_drawing_category" msgid="6755716469267367852">"Bildschirmdarstellung"</string> <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardwarebeschleunigtes Rendering"</string> <string name="media_category" msgid="4388305075496848353">"Medien"</string> <string name="debug_monitoring_category" msgid="7640508148375798343">"Überwachung"</string> <string name="strict_mode" msgid="1938795874357830695">"Strikter Modus aktiviert"</string> - <string name="strict_mode_summary" msgid="142834318897332338">"Bei längeren Aktionen im Hauptthread Bildschirm kurz einblenden"</string> + <string name="strict_mode_summary" msgid="142834318897332338">"Bei langen App-Operationen im Hauptthread blinkt Bildschirm"</string> <string name="pointer_location" msgid="6084434787496938001">"Zeigerposition"</string> <string name="pointer_location_summary" msgid="840819275172753713">"Overlay mit aktuellen Daten zu Tippaktionen"</string> <string name="show_touches" msgid="2642976305235070316">"Fingertipps anzeigen"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Visuelles Feedback für Fingertipps anzeigen"</string> - <string name="show_screen_updates" msgid="5470814345876056420">"Oberflächenaktualisierungen"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Flash für gesamte Fensteroberfläche bei Aktualisierung"</string> + <string name="show_screen_updates" msgid="5470814345876056420">"Oberflächenaktualisierungen anzeigen"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Gesamte Fensteroberflächen blinken bei Aktualisierung"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Updates anzeigen"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Flash-Ansicht im Fenster, wenn dargestellt"</string> - <string name="show_hw_layers_updates" msgid="5645728765605699821">"Hardwareebenen-Updates"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Ansichten in Fenstern blinken beim Rendern"</string> + <string name="show_hw_layers_updates" msgid="5645728765605699821">"Hardwareebenen-Updates anzeigen"</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Hardwareebenen blinken beim Aktualisieren grün"</string> - <string name="debug_hw_overdraw" msgid="2968692419951565417">"Debugging – GPU-Überschneidung"</string> + <string name="debug_hw_overdraw" msgid="2968692419951565417">"GPU-Overdraw debuggen"</string> <string name="disable_overlays" msgid="2074488440505934665">"HW-Overlays deaktivieren"</string> - <string name="disable_overlays_summary" msgid="3578941133710758592">"GPU immer für Bildschirmaufbau verwenden"</string> + <string name="disable_overlays_summary" msgid="3578941133710758592">"Für Bildschirm-Compositing immer GPU verwenden"</string> <string name="simulate_color_space" msgid="6745847141353345872">"Farbraum simulieren"</string> <string name="enable_opengl_traces_title" msgid="6790444011053219871">"OpenGL-Traces aktivieren"</string> <string name="usb_audio_disable_routing" msgid="8114498436003102671">"USB-Audiorouting deaktivieren"</string> <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Autom. Routing an externe USB-Audiogeräte deaktivieren"</string> - <string name="debug_layout" msgid="5981361776594526155">"Layoutgrenzen einblenden"</string> + <string name="debug_layout" msgid="5981361776594526155">"Layoutgrenzen anzeigen"</string> <string name="debug_layout_summary" msgid="2001775315258637682">"Clip-Begrenzungen, Ränder usw. anzeigen"</string> <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL-Layout erzwingen"</string> - <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"RTL-Bildschirmlayout für alle Sprachen erzwingen"</string> + <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Für alle Sprachen wird das RTL-Bildschirmlayout (linksläufig) verwendet"</string> <string name="force_msaa" msgid="7920323238677284387">"4x MSAA erzwingen"</string> - <string name="force_msaa_summary" msgid="9123553203895817537">"4x MSAA in OpenGL ES 2.0-Apps aktivieren"</string> + <string name="force_msaa_summary" msgid="9123553203895817537">"In OpenGL ES 2.0-Apps 4x MSAA aktivieren"</string> <string name="show_non_rect_clip" msgid="505954950474595172">"Nicht rechteckige Clip-Operationen debuggen"</string> <string name="track_frame_time" msgid="6094365083096851167">"HWUI-Rendering für Profil"</string> - <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU-Debugging-Ebene aktivieren"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Laden von GPU-Debugging-Ebene für Debugging-Apps erlauben"</string> + <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU-Debug-Ebenen zulassen"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Debug-Apps das Laden von GPU-Debug-Ebenen erlauben"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Maßstab Fensteranimation"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Maßstab Übergangsanimation"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Maßstab für Animatorzeit"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Sekundäre Displays simulieren"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Apps"</string> - <string name="immediately_destroy_activities" msgid="1579659389568133959">"Aktionen nicht speichern"</string> + <string name="immediately_destroy_activities" msgid="1579659389568133959">"Aktivitäten nicht speichern"</string> <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Aktivität löschen, sobald der Nutzer diese beendet"</string> - <string name="app_process_limit_title" msgid="4280600650253107163">"Hintergrundprozesslimit"</string> - <string name="show_all_anrs" msgid="4924885492787069007">"Hintergrund-ANRs anzeigen"</string> - <string name="show_all_anrs_summary" msgid="6636514318275139826">"Kleines Fenster \"App reagiert nicht\" für Hintergrund-Apps einblenden"</string> - <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Warnungen für Benachrichtigungskanäle einblenden"</string> - <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Blendet Warnungen auf dem Display ein, wenn eine App eine Benachrichtigung ohne gültigen Kanal sendet"</string> - <string name="force_allow_on_external" msgid="3215759785081916381">"Externe Speichernutzung von Apps erlauben"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string> - <string name="force_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string> - <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Größe aller Aktivitäten an den Mehrfenstermodus anpassen, unabhängig von den Manifestwerten."</string> + <string name="app_process_limit_title" msgid="4280600650253107163">"Limit für Hintergrundprozesse"</string> + <string name="show_all_anrs" msgid="4924885492787069007">"Absturzmeldungen für Hintergrund-Apps anzeigen"</string> + <string name="show_all_anrs_summary" msgid="6636514318275139826">"Bei Abstürzen von Hintergrund-Apps \"App reagiert nicht\"-Dialog anzeigen"</string> + <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Benachrichtigungskanal-Warnungen anzeigen"</string> + <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Bei Benachrichtigungen ohne gültigen Kanal wird eine Warnung angezeigt"</string> + <string name="force_allow_on_external" msgid="3215759785081916381">"Sperrung des externen Speichers für alle Apps aufheben"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Jede App kann, ungeachtet der Manifestwerte, in den externen Speicher geschrieben werden"</string> + <string name="force_resizable_activities" msgid="8615764378147824985">"Aktivitätengröße darf immer angepasst werden"</string> + <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Die Größe aller Aktivitäten darf, ungeachtet der Manifestwerte, für die Mehrfensterdarstellung angepasst werden"</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Freiform-Fenster zulassen"</string> - <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Experimentelle Freiform-Fenster unterstützen."</string> - <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop-Sicherungspasswort"</string> - <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt."</string> + <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Unterstützung für experimentelle Freiform-Fenster aktivieren"</string> + <string name="local_backup_password_title" msgid="3860471654439418822">"Passwort für Desktop-Sicherung"</string> + <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt"</string> <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen tippen"</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"Neues Sicherungspasswort festgelegt"</string> <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Das neue Passwort und die Bestätigung stimmen nicht überein."</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index 86bcf717214b..68b52275129e 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -216,7 +216,7 @@ <string name="mock_location_app" msgid="7966220972812881854">"Valige asukohateavet imiteeriv rakendus"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"Asukohateavet imiteeriv rakendus on määramata"</string> <string name="mock_location_app_set" msgid="8966420655295102685">"Asukohateavet imiteeriv rakendus: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> - <string name="debug_networking_category" msgid="7044075693643009662">"Võrgustik"</string> + <string name="debug_networking_category" msgid="7044075693643009662">"Võrgundus"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Juhtmeta ekraaniühenduse sertifitseerimine"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Luba WiFi sõnaline logimine"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Hoia mobiilne andmeside alati aktiivne"</string> @@ -294,8 +294,8 @@ <string name="show_touches_summary" msgid="6101183132903926324">"Kuvab puudutuste visuaalse tagasiside"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Näita pinna värskendusi"</string> <string name="show_screen_updates_summary" msgid="2569622766672785529">"Akna pinna värskendamiseks kirjuta kogu akna pind üle"</string> - <string name="show_hw_screen_updates" msgid="4117270979975470789">"Kuva ekraanikuva värsk."</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Joonistades kirjuta akende kuvad üle"</string> + <string name="show_hw_screen_updates" msgid="4117270979975470789">"Kuva ekraanikuva värskendusi"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Joonistades vilguta akende sisekuvasid"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Kuva riistvarakihtide värskendusi"</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Riistvara kihid vilguvad värskendamisel roheliselt"</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"Silu GPU ülejoonistust"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index c5a672469dc1..3cc66178cdf3 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -419,7 +419,7 @@ <item msgid="1286113608943010849">"% 100"</item> </string-array> <string name="charge_length_format" msgid="8978516217024434156">"Duela <xliff:g id="ID_1">%1$s</xliff:g>"</string> - <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> guztiz kargatu arte"</string> + <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> geratzen dira"</string> <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Txikia"</string> <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Lehenetsia"</string> <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Handia"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index d036446ddf39..6ea317d7042e 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -293,9 +293,9 @@ <string name="show_touches" msgid="2642976305235070316">"Näytä kosketus"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Anna visuaalista palautetta kosketuksesta."</string> <string name="show_screen_updates" msgid="5470814345876056420">"Näytä pintapäivitykset"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Väläytä koko ikkunoiden pinnat päivitettäessä"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Väläytä koko ikkunoiden pinnat päivitettäessä."</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Näytä näyttöpäivitykset"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Näytä ikkunoiden sisältö piirtämisen yhteydessä"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Näytä ikkunoiden sisältö piirtämisen yhteydessä."</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Näytä laitteistotason päivitykset"</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Näytä laitteistotasot vihreinä niiden päivittyessä."</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"GPU-objektien päällekkäisyys"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index d964ee4293d4..27d78854a2e0 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -203,10 +203,10 @@ <string name="enable_adb" msgid="7982306934419797485">"Débogage USB"</string> <string name="enable_adb_summary" msgid="4881186971746056635">"Mode débogage lorsqu\'un câble USB est connecté"</string> <string name="clear_adb_keys" msgid="4038889221503122743">"Annuler autorisations pour débog. USB"</string> - <string name="bugreport_in_power" msgid="7923901846375587241">"Raccourci vers rapport d\'erreur"</string> - <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Afficher un bouton dans le menu de démarrage permettant de créer un rapport d\'erreur"</string> - <string name="keep_screen_on" msgid="1146389631208760344">"Rester activé"</string> - <string name="keep_screen_on_summary" msgid="2173114350754293009">"L\'écran ne se met jamais en veille lors du chargement."</string> + <string name="bugreport_in_power" msgid="7923901846375587241">"Raccourci vers rapport de bug"</string> + <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Afficher un bouton dans le menu de démarrage permettant de créer un rapport de bug"</string> + <string name="keep_screen_on" msgid="1146389631208760344">"Écran toujours actif"</string> + <string name="keep_screen_on_summary" msgid="2173114350754293009">"L\'écran ne se met jamais en veille lorsqu\'il est en charge"</string> <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Activer journaux HCI Bluetooth"</string> <string name="bt_hci_snoop_log_summary" msgid="8857606786588106495">"Capturer les paquets Bluetooth. (Activer/Désactiver le Bluetooth après avoir modifié ce paramètre)"</string> <string name="oem_unlock_enable" msgid="6040763321967327691">"Déverrouillage OEM"</string> @@ -215,7 +215,7 @@ <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"AVERTISSEMENT : Les fonctionnalités de protection de l\'appareil sont désactivées tant que ce paramètre est activé."</string> <string name="mock_location_app" msgid="7966220972812881854">"Sélectionner l\'application de position fictive"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"Aucune application de position fictive définie"</string> - <string name="mock_location_app_set" msgid="8966420655295102685">"Application de position fictive : \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> + <string name="mock_location_app_set" msgid="8966420655295102685">"Application de position fictive : <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Mise en réseau"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certification affichage sans fil"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Autoriser enreg. infos Wi-Fi détaillées"</string> @@ -247,7 +247,7 @@ <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler plus infos Wi-Fi, afficher par RSSI de SSID dans outil sélection Wi-Fi"</string> <string name="wifi_metered_label" msgid="4514924227256839725">"Facturé à l\'usage"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Non facturé à l\'usage"</string> - <string name="select_logd_size_title" msgid="7433137108348553508">"Tailles mémoires tampons enregistr."</string> + <string name="select_logd_size_title" msgid="7433137108348553508">"Tailles des tampons de l\'enregistreur"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Tailles enreg. par tampon journal"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Effacer l\'espace de stockage persistant de l\'enregistreur ?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Lorsque nous n\'effectuons plus de suivi avec l\'enregistreur persistant, nous sommes tenus d\'effacer les données associées à ce dernier qui sont stockées sur votre appareil."</string> @@ -257,7 +257,7 @@ <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Sélectionner une configuration USB"</string> <string name="allow_mock_location" msgid="2787962564578664888">"Autoriser les positions fictives"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Autoriser les positions fictives"</string> - <string name="debug_view_attributes" msgid="6485448367803310384">"Activer inspect. attribut affich."</string> + <string name="debug_view_attributes" msgid="6485448367803310384">"Inspection des attributs d\'affichage"</string> <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Maintenir les données mobiles à l\'état actif, même lorsque le Wi‑Fi est actif (pour changer rapidement de réseau)"</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Utiliser l\'accélération matérielle pour le partage de connexion, si disponible"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Autoriser le débogage USB ?"</string> @@ -266,7 +266,7 @@ <string name="dev_settings_warning_title" msgid="7244607768088540165">"Activer les paramètres de développement ?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Vérifier les applis via USB"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifier que les applications installées par ADB/ADT ne présentent pas de comportement dangereux"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Les appareils Bluetooth seront affichés sans nom (adresse MAC uniquement)"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Désactive la fonctionnalité de volume absolu du Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé"</string> <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string> @@ -280,7 +280,7 @@ <string name="select_application" msgid="5156029161289091703">"Sélectionner une appli"</string> <string name="no_application" msgid="2813387563129153880">"Aucune"</string> <string name="wait_for_debugger" msgid="1202370874528893091">"Attendre l\'intervention du débogueur"</string> - <string name="wait_for_debugger_summary" msgid="1766918303462746804">"L\'application déboguée attend d\'être liée au débogueur pour s\'exécuter."</string> + <string name="wait_for_debugger_summary" msgid="1766918303462746804">"L\'application déboguée attend d\'être liée au débogueur pour s\'exécuter"</string> <string name="debug_input_category" msgid="1811069939601180246">"Saisie"</string> <string name="debug_drawing_category" msgid="6755716469267367852">"Tracé"</string> <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Accélération matérielle"</string> @@ -313,8 +313,8 @@ <string name="force_msaa_summary" msgid="9123553203895817537">"Activer MSAA 4x dans les applications OpenGL ES 2.0"</string> <string name="show_non_rect_clip" msgid="505954950474595172">"Déboguer opé. de découpage non rect."</string> <string name="track_frame_time" msgid="6094365083096851167">"Rendu HWUI du profil"</string> - <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activer couches débogage GPU"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Autoriser charg. couches débogage GPU pour applis débogage"</string> + <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activer les couches de débogage GPU"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Autoriser le chargement de couches de débogage GPU"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Échelle animation fenêtres"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Échelle anim. transitions"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Échelle durée animation"</string> @@ -333,8 +333,8 @@ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permettre de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste"</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string> <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activer la compatibilité avec les fenêtres de forme libre expérimentales"</string> - <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string> - <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string> + <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe de sauvegarde PC"</string> + <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement"</string> <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Appuyez pour modifier ou supprimer le mot de passe de sauvegarde complète sur PC."</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string> <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string> diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml index a7325c20f0f0..0ead894ebc28 100644 --- a/packages/SettingsLib/res/values-gl/arrays.xml +++ b/packages/SettingsLib/res/values-gl/arrays.xml @@ -59,9 +59,9 @@ <item msgid="45075631231212732">"Utilizar sempre a comprobación HDCP"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> - <item msgid="3966341281672645384">"Opción desactivada"</item> + <item msgid="3966341281672645384">"Desactivada"</item> <item msgid="1969681323976948639">"Está activado o filtrado"</item> - <item msgid="8719029132154020716">"Opción activada"</item> + <item msgid="8719029132154020716">"Activada"</item> </string-array> <string-array name="bluetooth_avrcp_versions"> <item msgid="5347678900838034763">"AVRCP 1.4 (predeterminado)"</item> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 19c75131f361..4ffb7c57d945 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -193,10 +193,10 @@ <string name="choose_profile" msgid="6921016979430278661">"Escoller perfil"</string> <string name="category_personal" msgid="1299663247844969448">"Persoal"</string> <string name="category_work" msgid="8699184680584175622">"Traballo"</string> - <string name="development_settings_title" msgid="215179176067683667">"Opcións de programador"</string> - <string name="development_settings_enable" msgid="542530994778109538">"Activar opcións de programador"</string> + <string name="development_settings_title" msgid="215179176067683667">"Opcións para programadores"</string> + <string name="development_settings_enable" msgid="542530994778109538">"Activar opcións para programadores"</string> <string name="development_settings_summary" msgid="1815795401632854041">"Definir as opcións de desenvolvemento de aplicacións"</string> - <string name="development_settings_not_available" msgid="4308569041701535607">"As opcións de programador non están dispoñibles para este usuario"</string> + <string name="development_settings_not_available" msgid="4308569041701535607">"As opcións para programadores non están dispoñibles para este usuario"</string> <string name="vpn_settings_not_available" msgid="956841430176985598">"A configuración da VPN non está dispoñible para este usuario"</string> <string name="tethering_settings_not_available" msgid="6765770438438291012">"A configuración da conexión compartida non está dispoñible para este usuario"</string> <string name="apn_settings_not_available" msgid="7873729032165324000">"A configuración do nome do punto de acceso non está dispoñible para este usuario"</string> @@ -207,7 +207,7 @@ <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostra un botón no menú de acendido para crear un informe de erros"</string> <string name="keep_screen_on" msgid="1146389631208760344">"Pantalla activa"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"A pantalla nunca estará en modo de suspensión durante a carga"</string> - <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Activar rexistro de busca HCI Bluetooth"</string> + <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Activar rexistro de Bluetooth HCI"</string> <string name="bt_hci_snoop_log_summary" msgid="8857606786588106495">"Capturar paquetes de Bluetooth. (Activa/desactiva o Bluetooth despois de cambiar esta opción)"</string> <string name="oem_unlock_enable" msgid="6040763321967327691">"Desbloqueo do OEM"</string> <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Permitir que se desbloqueo o cargador de inicio"</string> @@ -247,18 +247,18 @@ <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumenta o nivel de rexistro da wifi, móstrao por SSID RSSI no selector de wifi"</string> <string name="wifi_metered_label" msgid="4514924227256839725">"De pago por consumo"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Sen pago por consumo"</string> - <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de rexistrador"</string> - <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Seleccionar tamaños por búfer"</string> - <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Queres borrar o almacenamento continuo do rexistrador?"</string> - <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Cando xa non se supervisa a actividade co rexistrador de forma continua, debemos borrar os datos do rexistrador almacenados no dispositivo."</string> - <string name="select_logpersist_title" msgid="7530031344550073166">"Gardar datos de rexistrador de forma continua"</string> + <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños do búfer do rexistrador"</string> + <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Seleccionar tamaño do rexistrador por búfer"</string> + <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Queres borrar o almacenamento persistente do rexistrador?"</string> + <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Cando xa non se supervisa a actividade co rexistrador de forma persistente, debemos borrar os datos do rexistrador almacenados no dispositivo."</string> + <string name="select_logpersist_title" msgid="7530031344550073166">"Gardar datos do rexistrador de forma persistente"</string> <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Seleccionar búfers de rexistro para gardalos de forma continua no dispositivo"</string> <string name="select_usb_configuration_title" msgid="2649938511506971843">"Seleccionar configuración USB"</string> <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Seleccionar configuración USB"</string> <string name="allow_mock_location" msgid="2787962564578664888">"Permitir localizacións falsas"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Permite localizacións falsas"</string> <string name="debug_view_attributes" msgid="6485448367803310384">"Activar a inspección de atributos de visualización"</string> - <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantén sempre os datos móbiles activos, aínda que a wifi estea activada (para un rápido cambio de rede)."</string> + <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantén sempre os datos móbiles activados, aínda que a wifi estea activa (para cambiar de rede rapidamente)"</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Se está dispoñible, úsase a aceleración de hardware para conexión compartida"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Queres permitir a depuración por USB?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"A depuración de erros USB está deseñada unicamente para fins de programación. Utilízaa para copiar datos entre o ordenador e o dispositivo, instalar aplicacións no dispositivo sen enviar notificacións e ler os datos do rexistro."</string> @@ -266,7 +266,7 @@ <string name="dev_settings_warning_title" msgid="7244607768088540165">"Permitir a configuración de programación?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Esta configuración só está destinada á programación. Esta pode provocar que o dispositivo e as aplicacións fallen ou se comporten incorrectamente."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicacións por USB"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar as aplicacións instaladas a través de ADB/ADT para detectar comportamento perigoso."</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comproba as aplicacións instaladas a través de ADB/ADT para detectar comportamento perigoso."</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Mostraranse dispositivos Bluetooth sen nomes (só enderezos MAC)"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva a función do volume absoluto do Bluetooth en caso de que se produzan problemas de volume cos dispositivos remotos, como volume demasiado alto ou falta de control."</string> <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string> @@ -287,55 +287,55 @@ <string name="media_category" msgid="4388305075496848353">"Multimedia"</string> <string name="debug_monitoring_category" msgid="7640508148375798343">"Supervisión"</string> <string name="strict_mode" msgid="1938795874357830695">"Modo estrito activado"</string> - <string name="strict_mode_summary" msgid="142834318897332338">"Pestanexa se aplicacións tardan moito no proceso principal"</string> + <string name="strict_mode_summary" msgid="142834318897332338">"Ilumínase se aplicacións tardan moito no proceso principal"</string> <string name="pointer_location" msgid="6084434787496938001">"Localización do punteiro"</string> - <string name="pointer_location_summary" msgid="840819275172753713">"Superpoñer datos dos toques na pantalla"</string> + <string name="pointer_location_summary" msgid="840819275172753713">"Superpón os datos dos toques na pantalla"</string> <string name="show_touches" msgid="2642976305235070316">"Mostrar toques"</string> - <string name="show_touches_summary" msgid="6101183132903926324">"Mostra a información visual dos toques"</string> + <string name="show_touches_summary" msgid="6101183132903926324">"Mostra a localización dos toques na pantalla"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Cambios de superficie"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Iluminar superficies de ventás ao actualizarse"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Ilumina as superficies de ventás ao actualizarse"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Mostrar actualizacións"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Actualiza as vistas das ventás creadas"</string> - <string name="show_hw_layers_updates" msgid="5645728765605699821">"Ver act. capas hardware"</string> - <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Iluminar capas hardware en verde ao actualizarse"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Ilumina as vistas das ventás creadas"</string> + <string name="show_hw_layers_updates" msgid="5645728765605699821">"Ver actualizacións de capas de hardware"</string> + <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Ilumina as capas de hardware en verde ao actualizárense"</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"Depurar superposición GPU"</string> - <string name="disable_overlays" msgid="2074488440505934665">"Desact. superposicións HW"</string> - <string name="disable_overlays_summary" msgid="3578941133710758592">"Utilizar sempre GPU para a composición da pantalla"</string> + <string name="disable_overlays" msgid="2074488440505934665">"Desactivar superposicións de hardware"</string> + <string name="disable_overlays_summary" msgid="3578941133710758592">"Utiliza sempre GPU para a composición da pantalla"</string> <string name="simulate_color_space" msgid="6745847141353345872">"Simular o espazo da cor"</string> <string name="enable_opengl_traces_title" msgid="6790444011053219871">"Activar rastros OpenGL"</string> - <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Desact. encamiñamento audio USB"</string> - <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Desact. encamiñamento aut. a periférico audio USB"</string> + <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Desactivar encamiñamento audio USB"</string> + <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Desactiva o encamiñamento automático a periféricos de audio USB"</string> <string name="debug_layout" msgid="5981361776594526155">"Mostrar límites de deseño"</string> <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra os límites dos clips, as marxes, etc."</string> <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar dirección do deseño RTL"</string> <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forza a dirección de pantalla a RTL (dereita a esquerda) para todas as configuración rexionais"</string> <string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string> - <string name="force_msaa_summary" msgid="9123553203895817537">"Activar MSAA 4x en aplicacións OpenGL ES 2.0"</string> - <string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operacións recorte non rectangulares"</string> + <string name="force_msaa_summary" msgid="9123553203895817537">"Activa MSAA 4x en aplicacións OpenGL ES 2.0"</string> + <string name="show_non_rect_clip" msgid="505954950474595172">"Depurar accións recorte non rectangulares"</string> <string name="track_frame_time" msgid="6094365083096851167">"Perfil procesamento HWUI"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Activar depuración da GPU"</string> <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permite capas da GPU para apps de depuración"</string> - <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala animación da ventá"</string> - <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala anim. transición"</string> + <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de animación da ventá"</string> + <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala animación-transición"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala duración animador"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simular pantallas secundarias"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Aplicacións"</string> <string name="immediately_destroy_activities" msgid="1579659389568133959">"Non manter actividades"</string> <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Destruír actividades cando o usuario non as use"</string> <string name="app_process_limit_title" msgid="4280600650253107163">"Límite procesos 2º plano"</string> - <string name="show_all_anrs" msgid="4924885492787069007">"Mostrar ANR en segundo plano"</string> + <string name="show_all_anrs" msgid="4924885492787069007">"Erros sen resposta en segundo plano"</string> <string name="show_all_anrs_summary" msgid="6636514318275139826">"Indica que unha aplicación en segundo plano non responde"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostrar avisos de notificacións"</string> <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra avisos cando unha aplicación publica notificacións sen unha canle válida"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permiso de aplicacións de forma externa"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permite que calquera aplicación apta se poida escribir nun almacenamento externo, independentemente dos valores expresados"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permite que calquera aplicación compatible se poida escribir nun almacenamento externo, independentemente dos valores do manifesto"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar o axuste do tamaño das actividades"</string> - <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite axustar o tamaño de todas as actividades para o modo multiventá, independentemente dos valores definidos."</string> + <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite axustar o tamaño de todas as actividades para o modo multiventá, independentemente dos valores do manifesto"</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Activar ventás de forma libre"</string> <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activa a compatibilidade con ventás de forma libre experimentais."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"As copias de seguranza de ordenador completas non están protexidas"</string> - <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string> + <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas de ordenador"</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo contrasinal da copia de seguranza definido"</string> <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"O contrasinal novo e a confirmación non coinciden"</string> <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Erro ao definir un contrasinal da copia de seguranza"</string> @@ -354,8 +354,8 @@ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Aplicación inactiva. Toca para alternar a configuración."</string> <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aplicación activa. Toca para alternar a configuración."</string> <string name="standby_bucket_summary" msgid="6567835350910684727">"Estado en espera da aplicación: <xliff:g id="BUCKET"> %s</xliff:g>"</string> - <string name="runningservices_settings_title" msgid="8097287939865165213">"En execución"</string> - <string name="runningservices_settings_summary" msgid="854608995821032748">"Comproba e controla os servizos actualmente en execución"</string> + <string name="runningservices_settings_title" msgid="8097287939865165213">"Servizos en uso"</string> + <string name="runningservices_settings_summary" msgid="854608995821032748">"Comproba e controla os servizos actualmente en uso"</string> <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string> <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementación de WebView"</string> <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Esta opción xa non é válida. Téntao de novo."</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index e812810547db..da59230ecd42 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -269,7 +269,7 @@ <string name="dev_settings_warning_title" msgid="7244607768088540165">"विकास सेटिंग की अनुमति दें?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"ये सेटिंग केवल विकास संबंधी उपयोग के प्रयोजन से हैं. वे आपके डिवाइस और उस पर स्थित ऐप्स को खराब कर सकती हैं या उनके दुर्व्यवहार का कारण हो सकती हैं."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"यूएसबी पर ऐप्लिकेशन की पुष्टि करें"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"नुकसानदेह व्यवहार के लिए ADB/ADT के द्वारा इंस्टॉल किए गए ऐप्स जाँचें."</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"नुकसानदेह व्यवहार के लिए ADB/ADT से इंस्टॉल किए गए ऐप्लिकेशन जाँचें."</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"बिना नाम वाले ब्लूटूथ डिवाइस (केवल MAC पते वाले) दिखाए जाएंगे"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूर के डिवाइस पर आवाज़ बहुत बढ़ जाने या उससे नियंत्रण हटने जैसी समस्याएं होने पर, यह ब्लूटूथ के ज़रिए आवाज़ के नियंत्रण की सुविधा रोक देता है."</string> <string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string> @@ -309,7 +309,7 @@ <string name="usb_audio_disable_routing" msgid="8114498436003102671">"यूएसबी ऑडियो रूटिंग बंद करें"</string> <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"यूएसबी ऑडियो पेरिफ़ेरल पर अपने आप रूटिंग बंद करें"</string> <string name="debug_layout" msgid="5981361776594526155">"लेआउट सीमाएं दिखाएं"</string> - <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमाएं, मार्जिन आदि दिखाएं."</string> + <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमाएं, मार्जिन वगैरह दिखाएं."</string> <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"लेआउट की दिशा दाएं से बाएं करें"</string> <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सभी भाषाओं के लिए स्क्रीन लेआउट की दिशा दाएं से बाएं रखें"</string> <string name="force_msaa" msgid="7920323238677284387">"4x MSAA को हर हाल में चालू करें"</string> @@ -340,7 +340,7 @@ <string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप के पूरे बैक अप फ़िलहाल सुरक्षित नहीं हैं"</string> <string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉप के पूरे बैक अप का पासवर्ड बदलने या हटाने के लिए टैप करें"</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"नया बैकअप पासवर्ड सेट किया गया"</string> - <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नया पासवर्ड तथा पुष्टि मेल नही खाते"</string> + <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नया पासवर्ड और पुष्टि मेल नही खाते"</string> <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"सुरक्षित पासवर्ड सेट करने में विफल रहा"</string> <string name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड हो रहा है…"</string> <string-array name="color_mode_names"> @@ -379,16 +379,16 @@ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यह सुविधा प्रायोगिक है और निष्पादन को प्रभावित कर सकती है."</string> <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string> <string name="power_remaining_settings_home_page" msgid="4845022416859002011">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> - <string name="power_remaining_duration_only" msgid="6123167166221295462">"बैटरी लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string> - <string name="power_discharging_duration" msgid="8848256785736335185">"बैटरी लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_remaining_duration_only" msgid="6123167166221295462">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string> + <string name="power_discharging_duration" msgid="8848256785736335185">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_duration_only_enhanced" msgid="4189311599812296592">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string> <string name="power_discharging_duration_enhanced" msgid="1992003260664804080">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <!-- no translation found for power_remaining_duration_only_short (9183070574408359726) --> <skip /> <string name="power_discharge_by_enhanced" msgid="2095821536747992464">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME">%1$s</xliff:g> तक चलेगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME">%1$s</xliff:g> तक चलेगी"</string> - <string name="power_discharge_by" msgid="6453537733650125582">"बैटरी लगभग <xliff:g id="TIME">%1$s</xliff:g> चलेगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="107616694963545745">"बैटरी लगभग <xliff:g id="TIME">%1$s</xliff:g> चलेगी"</string> + <string name="power_discharge_by" msgid="6453537733650125582">"बैटरी करीब <xliff:g id="TIME">%1$s</xliff:g> चलेगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only" msgid="107616694963545745">"बैटरी करीब <xliff:g id="TIME">%1$s</xliff:g> चलेगी"</string> <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> तक"</string> <!-- no translation found for power_suggestion_extend_battery (4401408879069551485) --> <skip /> diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml index 867f9eaa73a8..06f743ec6d0b 100644 --- a/packages/SettingsLib/res/values-in/arrays.xml +++ b/packages/SettingsLib/res/values-in/arrays.xml @@ -165,11 +165,11 @@ </string-array> <string-array name="select_logd_size_summaries"> <item msgid="6921048829791179331">"Nonaktif"</item> - <item msgid="2969458029344750262">"64 K/penyangga log"</item> - <item msgid="1342285115665698168">"256 K/penyangga log"</item> - <item msgid="1314234299552254621">"1 M/penyangga log"</item> - <item msgid="3606047780792894151">"4 M/penyangga log"</item> - <item msgid="5431354956856655120">"16 M/penyangga log"</item> + <item msgid="2969458029344750262">"64 K/buffer log"</item> + <item msgid="1342285115665698168">"256 K/buffer log"</item> + <item msgid="1314234299552254621">"1 M/buffer log"</item> + <item msgid="3606047780792894151">"4 M/buffer log"</item> + <item msgid="5431354956856655120">"16 M/buffer log"</item> </string-array> <string-array name="select_logpersist_titles"> <item msgid="1744840221860799971">"Nonaktif"</item> @@ -181,7 +181,7 @@ <item msgid="2216470072500521830">"Nonaktif"</item> <item msgid="172978079776521897">"Semua penyangga log"</item> <item msgid="3873873912383879240">"Semua kecuali penyangga log radio"</item> - <item msgid="8489661142527693381">"khusus penyangga log kernel"</item> + <item msgid="8489661142527693381">"khusus buffer log kernel"</item> </string-array> <string-array name="window_animation_scale_entries"> <item msgid="8134156599370824081">"Animasi mati"</item> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 1a0a4abf5889..50e305ee00d2 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -291,13 +291,13 @@ <string name="pointer_location" msgid="6084434787496938001">"Lokasi penunjuk"</string> <string name="pointer_location_summary" msgid="840819275172753713">"Hamparan layar menampilkan data sentuhan saat ini"</string> <string name="show_touches" msgid="2642976305235070316">"Tampilkan tap"</string> - <string name="show_touches_summary" msgid="6101183132903926324">"Tampilkan masukan visual untuk ketukan"</string> + <string name="show_touches_summary" msgid="6101183132903926324">"Tampilkan masukan visual untuk tap"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Lihat pembaruan permukaan"</string> <string name="show_screen_updates_summary" msgid="2569622766672785529">"Sorot seluruh permukaan jendela saat diperbarui"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Tampilkan update tampilan"</string> <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Tampilan cepat dalam jendela saat digambar"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Tunjukkan update lapisan hardware"</string> - <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Lapisan hardware berkedip hijau saat memperbarui"</string> + <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Lapisan hardware berkedip hijau saat mengupdate"</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"Debug overdraw oleh GPU"</string> <string name="disable_overlays" msgid="2074488440505934665">"Nonaktifkan lapisan HW"</string> <string name="disable_overlays_summary" msgid="3578941133710758592">"Selalu gunakan GPU untuk pengomposisian layar"</string> @@ -320,8 +320,8 @@ <string name="animator_duration_scale_title" msgid="3406722410819934083">"Skala durasi animator"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simulasikan tampilan sekunder"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Aplikasi"</string> - <string name="immediately_destroy_activities" msgid="1579659389568133959">"Jangan simpan kegiatan"</string> - <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Hancurkan tiap kegiatan setelah ditinggal pengguna"</string> + <string name="immediately_destroy_activities" msgid="1579659389568133959">"Jangan simpan aktivitas"</string> + <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Hancurkan tiap aktivitas setelah ditinggal pengguna"</string> <string name="app_process_limit_title" msgid="4280600650253107163">"Batas proses background"</string> <string name="show_all_anrs" msgid="4924885492787069007">"Tampilkan ANR background"</string> <string name="show_all_anrs_summary" msgid="6636514318275139826">"Tampilkan dialog Aplikasi Tidak Merespons untuk aplikasi yang berjalan di background"</string> @@ -367,7 +367,7 @@ <string name="button_convert_fbe" msgid="5152671181309826405">"Hapus dan konversi…"</string> <string name="picture_color_mode" msgid="4560755008730283695">"Mode warna gambar"</string> <string name="picture_color_mode_desc" msgid="1141891467675548590">"Gunakan sRGB"</string> - <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Nonaktifkan"</string> + <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Dinonaktifkan"</string> <string name="daltonizer_mode_monochromacy" msgid="8485709880666106721">"Monokromasi"</string> <string name="daltonizer_mode_deuteranomaly" msgid="5475532989673586329">"Deuteromali (merah-hijau)"</string> <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"Protanomali (merah-hijau)"</string> diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml index 7d316ab8433d..eb2c1342ff89 100644 --- a/packages/SettingsLib/res/values-it/arrays.xml +++ b/packages/SettingsLib/res/values-it/arrays.xml @@ -59,7 +59,7 @@ <item msgid="45075631231212732">"Usa sempre la verifica HDCP"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> - <item msgid="3966341281672645384">"Non attiva"</item> + <item msgid="3966341281672645384">"Non attivo"</item> <item msgid="1969681323976948639">"Filtro attivo"</item> <item msgid="8719029132154020716">"Attiva"</item> </string-array> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 2169b0cb13c6..fdd1b41d3c1d 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -201,7 +201,7 @@ <string name="tethering_settings_not_available" msgid="6765770438438291012">"Le impostazioni Tethering non sono disponibili per questo utente"</string> <string name="apn_settings_not_available" msgid="7873729032165324000">"Le impostazioni del nome punto di accesso non sono disponibili per questo utente"</string> <string name="enable_adb" msgid="7982306934419797485">"Debug USB"</string> - <string name="enable_adb_summary" msgid="4881186971746056635">"Modalità debug quando è connesso USB"</string> + <string name="enable_adb_summary" msgid="4881186971746056635">"Modalità debug quando è connesso tramite USB"</string> <string name="clear_adb_keys" msgid="4038889221503122743">"Revoca autorizzazioni debug USB"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"Scorciatoria segnalazione bug"</string> <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostra un pulsante per segnalare i bug nel menu di accensione"</string> @@ -227,7 +227,7 @@ <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Seleziona versione Bluetooth AVRCP"</string> <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="8436224899475822557">"Attiva il codec audio Bluetooth\nSelezione"</string> - <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frequenza di campionamento audio Bluetooth"</string> + <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Freq. di campionamento audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="8010380028880963535">"Attiva il codec audio Bluetooth\nSelezione: Frequenza di campionamento"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit per campione dell\'audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="8063859754619484760">"Attiva il codec audio Bluetooth\nSelezione: bit per campione"</string> @@ -251,14 +251,14 @@ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Seleziona dimensioni Logger per buffer log"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Cancellare i dati nello spazio di archiviazione permanente del logger?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Quando il monitoraggio tramite logger permanente viene interrotto, siamo obbligati a eliminare i dati del logger memorizzati sul dispositivo."</string> - <string name="select_logpersist_title" msgid="7530031344550073166">"Salva dati del logger sul dispositivo in modo permanente"</string> + <string name="select_logpersist_title" msgid="7530031344550073166">"Salva dati del logger in modo permanente"</string> <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Seleziona i buffer log da memorizzare in modo permanente sul dispositivo"</string> <string name="select_usb_configuration_title" msgid="2649938511506971843">"Seleziona configurazione USB"</string> <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Seleziona configurazione USB"</string> <string name="allow_mock_location" msgid="2787962564578664888">"Posizioni fittizie"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Consenti posizioni fittizie"</string> <string name="debug_view_attributes" msgid="6485448367803310384">"Attiva controllo attributi visualizzazione"</string> - <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantieni sempre i dati mobili attivi, anche se il Wi‑Fi è attivo (per un passaggio fra reti rapido)."</string> + <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantieni sempre i dati mobili attivi, anche se il Wi‑Fi è attivo (per un passaggio fra reti rapido)"</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Utilizza l\'accelerazione hardware per il tethering se disponibile"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Consentire debug USB?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"Il debug USB è solo a scopo di sviluppo. Utilizzalo per copiare dati tra il computer e il dispositivo, per installare applicazioni sul tuo dispositivo senza notifica e per leggere i dati dei log."</string> @@ -266,9 +266,9 @@ <string name="dev_settings_warning_title" msgid="7244607768088540165">"Consentire impostazioni di sviluppo?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Queste impostazioni sono utilizzabili solo a scopo di sviluppo. Possono causare l\'arresto o il comportamento anomalo del dispositivo e delle applicazioni su di esso."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica app tramite USB"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le app installate tramite ADB/ADT non abbiano un comportamento dannoso."</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le app installate tramite ADB/ADT non abbiano un comportamento dannoso"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Verranno mostrati solo dispositivi Bluetooth senza nome (solo indirizzo MAC)"</string> - <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disattiva la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo."</string> + <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disattiva la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo"</string> <string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string> <string name="enable_terminal_summary" msgid="67667852659359206">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string> <string name="hdcp_checking_title" msgid="8605478913544273282">"Verifica HDCP"</string> @@ -294,7 +294,7 @@ <string name="show_touches_summary" msgid="6101183132903926324">"Mostra feedback visivi per i tocchi"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Aggiornamenti superficie"</string> <string name="show_screen_updates_summary" msgid="2569622766672785529">"Flash delle superfici delle finestre all\'aggiornamento"</string> - <string name="show_hw_screen_updates" msgid="4117270979975470789">"Aggiornamenti visualizz."</string> + <string name="show_hw_screen_updates" msgid="4117270979975470789">"Aggiornam. visualizzazione"</string> <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Flash visualizzazioni dentro finestre se disegnate"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Aggiornam. livelli hardware"</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Lampeggia verde se aggiornam. livelli hardware"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index f163ddc7fa8a..26ec1077c095 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -324,7 +324,7 @@ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"ユーザーが離れたアクティビティを直ちに破棄する"</string> <string name="app_process_limit_title" msgid="4280600650253107163">"バックグラウンドプロセスの上限"</string> <string name="show_all_anrs" msgid="4924885492787069007">"バックグラウンド ANR の表示"</string> - <string name="show_all_anrs_summary" msgid="6636514318275139826">"バックグラウンド アプリが応答しない場合に通知"</string> + <string name="show_all_anrs_summary" msgid="6636514318275139826">"バックグラウンド アプリが応答しない場合にダイアログを表示"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"通知チャネルの警告を表示"</string> <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"アプリから有効なチャネルのない通知が投稿されたときに画面上に警告を表示します"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"外部ストレージへのアプリの書き込みを許可"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 7c52ba38a1d5..034a8f48740b 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -74,9 +74,9 @@ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"Жалғанды (аудиосыз), батарея заряды: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"Жалғанды (телефонсыз не аудиосыз), батарея заряды: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_active_battery_level" msgid="3149689299296462009">"Қосулы, батарея қуаты: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="bluetooth_active_battery_level_untethered" msgid="6662649951391456747">"Қосулы, С: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батарея, О: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарея"</string> + <string name="bluetooth_active_battery_level_untethered" msgid="6662649951391456747">"Қосулы, С: батарея заряды – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, О: батарея заряды – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> <string name="bluetooth_battery_level" msgid="1447164613319663655">"Батарея қуаты: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="bluetooth_battery_level_untethered" msgid="5974406100211667177">"С: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батарея, О: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарея"</string> + <string name="bluetooth_battery_level_untethered" msgid="5974406100211667177">"С: батарея заряды – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, О: батарея заряды – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> <string name="bluetooth_active_no_battery_level" msgid="8380223546730241956">"Қосулы"</string> <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Meдиа аудиосы"</string> <string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефон қоңыраулары"</string> @@ -207,9 +207,9 @@ <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Қуат мәзірінде қате туралы хабарлауға арналған түймені көрсету"</string> <string name="keep_screen_on" msgid="1146389631208760344">"Ояу тұру"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"Зарядтау кезінде экран ұйықтамайды"</string> - <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Bluetooth HCI snoop тіркелімін қосу"</string> + <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Bluetooth HCI қадағалау журналын қосу"</string> <string name="bt_hci_snoop_log_summary" msgid="8857606786588106495">"Bluetooth пакеттерін алу (осы параметрді өзгерткен соң, Bluetooth-ды қосыңыз немесе өшіріңіз)"</string> - <string name="oem_unlock_enable" msgid="6040763321967327691">"OEM бекітпесін ашу"</string> + <string name="oem_unlock_enable" msgid="6040763321967327691">"OEM құлып ашу функциясы"</string> <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Жүктеуші бекітпесін ашуға рұқсат ету"</string> <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"OEM бекітпесін ашуға рұқсат ету керек пе?"</string> <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"ЕСКЕРТУ: осы параметр қосулы кезде, құрылғыны қорғау мүмкіндіктері жұмыс істемейді."</string> @@ -225,13 +225,13 @@ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</string> <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP нұсқасы"</string> <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Bluetooth AVRCP нұсқасын таңдау"</string> - <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудимазмұн кодегі"</string> + <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудиокодегі"</string> <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="8436224899475822557">"Bluetooth аудиокодегін іске қосу\nТаңдау"</string> - <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудиомазмұны бойынша іріктеу жиілігі"</string> + <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth арқылы дыбыс іріктеу жиілігі"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="8010380028880963535">"Bluetooth аудиокодегін іске қосу\nТаңдау: іріктеу жылдамдығы"</string> - <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth аудиомазмұны бойынша разрядтылық мөлшері"</string> + <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth арқылы дыбыстың разрядтылық мөлшері"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="8063859754619484760">"Bluetooth аудиокодегін іске қосу\nТаңдау: разрядтылық"</string> - <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth аудиомазмұны бойынша арна режимі"</string> + <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth дыбыстық арна режимі"</string> <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="7234956835280563341">"Bluetooth аудиокодегін іске қосу\nТаңдау: арна режимі"</string> <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth LDAC аудиокодегі: ойнату сапасы"</string> <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="6893955536658137179">"Bluetooth үшін LDAC аудиокодегін іске қосу\nТаңдау: ойнату сапасы"</string> @@ -258,7 +258,7 @@ <string name="allow_mock_location" msgid="2787962564578664888">"Жасанды аймақтарға рұқсат беру"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Жасанды аймақтарды пайдалануға рұқсат беру"</string> <string name="debug_view_attributes" msgid="6485448367803310384">"Көру төлсипатын тексеруді қосу"</string> - <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Wi‑Fi қосулы кезде де ұялы деректерді белсенді етіп ұстау (желіні жылдам ауыстыру үшін)."</string> + <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Wi‑Fi қосулы кезде де мобильдік интернетті өшірмеу (желіні жылдам ауыстыру үшін)"</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Қолжетімді болса тетерингтің аппараттық жеделдетуін пайдалану"</string> <string name="adb_warning_title" msgid="6234463310896563253">"USB жөндеулеріне рұқсат берілсін бе?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"USB жөндеу дамыту мақсаттарына ғана арналған. Оны компьютер және құрылғы арасында дерек көшіру, құрылғыға ескертусіз қолданба орнату және тіркелім деректерін оқу үшін қолданыңыз."</string> @@ -280,7 +280,7 @@ <string name="select_application" msgid="5156029161289091703">"Қолданба таңдау"</string> <string name="no_application" msgid="2813387563129153880">"Ешнәрсе"</string> <string name="wait_for_debugger" msgid="1202370874528893091">"Жөндеушіні күту"</string> - <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Орындау алдында бекіту үшін жөнделген қолданба жөндеушіні күтеді."</string> + <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Орындау алдында жөнделетін қолданба жөндеушіні күтеді"</string> <string name="debug_input_category" msgid="1811069939601180246">"Кіріс"</string> <string name="debug_drawing_category" msgid="6755716469267367852">"Сызу"</string> <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Бейнелеуді жабдықпен жылдамдату"</string> @@ -292,8 +292,8 @@ <string name="pointer_location_summary" msgid="840819275172753713">"Экран бетіне түртілген элемент дерегі көрсетіледі"</string> <string name="show_touches" msgid="2642976305235070316">"Түрту қимылын көрсету"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Түрту қимылын экраннан көрсету"</string> - <string name="show_screen_updates" msgid="5470814345876056420">"Беттің жаңарғанын көрсету"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Жаңарғанда, терезе беттерін жыпылықтату"</string> + <string name="show_screen_updates" msgid="5470814345876056420">"Бедердің жаңарғанын көрсету"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Бедері жаңарғанда, терезені түгелдей жыпылықтату"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Көру аумағын жаңартуды көрсету"</string> <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Терезелерде жаңартылған аумақтарды жарықтандыру"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Аппараттық қабат жаңартуларын көрсету"</string> @@ -306,7 +306,7 @@ <string name="usb_audio_disable_routing" msgid="8114498436003102671">"USB-мен аудио жіберуді өшіру"</string> <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Сыртқы USB аудио құрылғыларына автоматты жіберуді өшіру"</string> <string name="debug_layout" msgid="5981361776594526155">"Жиектерді көрсету"</string> - <string name="debug_layout_summary" msgid="2001775315258637682">"Қию шектерін, жиектерін, т.б көрсету."</string> + <string name="debug_layout_summary" msgid="2001775315258637682">"Қию шегін, шеттерді, т.б. көрсету"</string> <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Оңнан солға орналастыру"</string> <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Экранның орналасу бағытын барлық тілдер үшін оңнан солға қарату"</string> <string name="force_msaa" msgid="7920323238677284387">"4x MSAA қолдану"</string> @@ -314,7 +314,7 @@ <string name="show_non_rect_clip" msgid="505954950474595172">"Тіктөртбұрышты емес қию қимылдарын жөндеу"</string> <string name="track_frame_time" msgid="6094365083096851167">"Профиль бойынша HWUI рендерингі"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU жөндеу қабаттарын қосу"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"GPU жқндеу қабаттарының жүктелуіне рұқсат ету"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"GPU жөндеу қабаттарының жүктелуіне рұқсат ету"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Терезе анимациясының өлшемі"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Ауысу анимациясының өлшемі"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Аниматор ұзақтығы"</string> @@ -326,9 +326,9 @@ <string name="show_all_anrs" msgid="4924885492787069007">"Фондық ANR-ларды көрсету"</string> <string name="show_all_anrs_summary" msgid="6636514318275139826">"Фондық қолданбалар үшін \"Қолданба жауап бермейді\" терезесін шығару"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Хабарландыру арнасының ескертулерін көрсету"</string> - <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Қолданба жарамсыз арна арқылы хабарландыру жариялағанда, экрандық ескертуді көрсетеді"</string> + <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Қолданба жарамсыз арна арқылы хабарландыру жариялағанда, экранға ескерту шығарады"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Сыртқы жадта қолданбаларға рұқсат ету"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Манифест мәндеріне қарамастан, кез келген қолданбаны сыртқы жадқа жазу мүмкіндігін береді"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттердің өлшемін өзгертуге рұқсат ету"</string> <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест мәндеріне қарамастан бірнеше терезе режимінде барлық әрекеттердің өлшемін өзгертуге рұқсат беру."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Еркін пішіндегі терезелерді қосу"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index b897e1efb372..e799d0c03284 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -295,7 +295,7 @@ <string name="show_screen_updates" msgid="5470814345876056420">"Экран жаңыруусун көрсөтүү"</string> <string name="show_screen_updates_summary" msgid="2569622766672785529">"Экран жаңырганда анын үстү жарык болот"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Жаңыртууларды көрсөтүү"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Тартканда көрүүлөрдү терезелердин ичинде көрсөтүү"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Тартканда экрандын четтерин жарык кылуу"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Аппараттык жаңыртууларды көрсөтүү"</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Жаңырган аппараттык деңгээлдер жашыл түскө боелот"</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"GPU мүчүлүштүктөрүн оңдоо"</string> diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml index 596408297396..e0560ba16314 100644 --- a/packages/SettingsLib/res/values-ml/arrays.xml +++ b/packages/SettingsLib/res/values-ml/arrays.xml @@ -26,7 +26,7 @@ <item msgid="8513729475867537913">"കണക്റ്റുചെയ്യുന്നു..."</item> <item msgid="515055375277271756">"പ്രാമാണീകരിക്കുന്നു..."</item> <item msgid="1943354004029184381">"IP വിലാസം നേടുന്നു..."</item> - <item msgid="4221763391123233270">"കണക്റ്റുചെയ്തു"</item> + <item msgid="4221763391123233270">"കണക്റ്റ് ചെയ്തു"</item> <item msgid="624838831631122137">"താൽക്കാലികമായി നിർത്തി"</item> <item msgid="7979680559596111948">"വിച്ഛേദിക്കുന്നു..."</item> <item msgid="1634960474403853625">"വിച്ഛേദിച്ചു"</item> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index af0b773f51a8..e4f17888e9a7 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -239,7 +239,7 @@ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"സ്വകാര്യ DNS"</string> <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"സ്വകാര്യ DNS മോഡ് തിരഞ്ഞെടുക്കുക"</string> <string name="private_dns_mode_off" msgid="8236575187318721684">"ഓഫ്"</string> - <string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"സ്വമേധയാ"</string> + <string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"സ്വയമേവ"</string> <string name="private_dns_mode_provider" msgid="8354935160639360804">"സ്വകാര്യ DNS ദാതാവിന്റെ ഹോസ്റ്റുനാമം"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ദാതാവിന്റെ ഹോസ്റ്റുനാമം നൽകുക"</string> <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"കണക്റ്റ് ചെയ്യാനായില്ല"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 55ac9e6cea72..78d9ed792982 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -265,7 +265,7 @@ <string name="adb_keys_warning_message" msgid="5659849457135841625">"Таны өмнө нь зөвшөөрөл өгсөн бүх компьютерээс USB дебаг хандалтыг нь хураах уу?"</string> <string name="dev_settings_warning_title" msgid="7244607768088540165">"Хөгжлийн тохиргоог зөвшөөрөх үү?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликейшнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string> - <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р тулгах"</string> + <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р баталгаажуулах"</string> <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Нэргүй Bluetooth төхөөрөмжийг (зөвхөн MAC хаяг) харуулна"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Хэт чанга дуугаралт эсвэл муу тохиргоо зэрэг алсын зайн төхөөрөмжийн дуугаралттай холбоотой асуудлын үед Bluetooth-ийн үнэмлэхүй дууны түвшинг идэвхгүй болго."</string> @@ -283,7 +283,7 @@ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Дебаг хийгдсэн апп гүйцэтгэхийнхээ өмнө дебаг-г хавсаргахыг хүлээнэ"</string> <string name="debug_input_category" msgid="1811069939601180246">"Оруулах"</string> <string name="debug_drawing_category" msgid="6755716469267367852">"Зураг"</string> - <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Техник хангамжийн хурдатгалтай үзүүлэлт"</string> + <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Техник хангамжийн хурдасгасан үзүүлэлт"</string> <string name="media_category" msgid="4388305075496848353">"Медиа"</string> <string name="debug_monitoring_category" msgid="7640508148375798343">"Мониторинг"</string> <string name="strict_mode" msgid="1938795874357830695">"Хатуу горимыг идэвхжүүлсэн"</string> @@ -324,7 +324,7 @@ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Үйлдэл бүрийг хэрэглэгч орхимогц нь устгах"</string> <string name="app_process_limit_title" msgid="4280600650253107163">"Далд процессын хязгаар"</string> <string name="show_all_anrs" msgid="4924885492787069007">"Цаана ANR-г харуулах"</string> - <string name="show_all_anrs_summary" msgid="6636514318275139826">"Апп хариу өгөхгүй байна гэсэн харилцах цонхыг Цаана байгаа аппад харуулах"</string> + <string name="show_all_anrs_summary" msgid="6636514318275139826">"Апп хариу өгөхгүй байна гэсэн харилцах цонхыг цаана байгаа аппад харуулах"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Мэдэгдлийн сувгийн анхааруулгыг харуулах"</string> <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Апп хүчинтэй суваггүйгээр мэдэгдэл гаргах үед дэлгэцэд сануулга харуулна"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Аппыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string> @@ -333,7 +333,7 @@ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string> <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлнэ үү."</string> - <string name="local_backup_password_title" msgid="3860471654439418822">"Десктоп нөөшлөлтийн нууц үг"</string> + <string name="local_backup_password_title" msgid="3860471654439418822">"Десктоп нөөцлөлтийн нууц үг"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Десктоп бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string> <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Компьютерийн бүтэн нөөцлөлтийн нууц үгийг өөрчлөх, устгах бол дарна уу"</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"Нөөцлөлтийн шинэ нууц үг тохирууллаа"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index b6654a1656d1..f4711aaf1495 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -266,7 +266,7 @@ <string name="dev_settings_warning_title" msgid="7244607768088540165">"विकास सेटिंग्जला अनुमती द्यायची?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"या सेटिंग्जचा हेतू फक्त विकास वापरासाठी आहे. त्यामुळे तुमचे डिव्हाइस आणि त्यावरील अॅप्लिकेशन ब्रेक होऊ शकतात किंवा नेहमीपेक्षा वेगळे वर्तन करू शकतात."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB वर अॅप्स पडताळून पाहा"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक वर्तनासाठी ADB/ADT द्वारे इंस्टॉल अॅप्स तपासा."</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक वर्तनासाठी ADB/ADT द्वारे इंस्टॉल अॅप्स तपासा."</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"नावांशिवाय ब्लूटूथ डीव्हाइस (फक्त MAC पत्ते) दाखवले जातील"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"रिमोट डिव्हाइसमध्ये सहन न होणारा मोठा आवाज किंवा नियंत्रणाचा अभाव यासारखी आवाजाची समस्या असल्यास ब्लूटूथ संपूर्ण आवाज वैशिष्ट्य बंद करते."</string> <string name="enable_terminal_title" msgid="95572094356054120">"स्थानिक टर्मिनल"</string> @@ -314,7 +314,7 @@ <string name="show_non_rect_clip" msgid="505954950474595172">"आयताकृती नसलेले क्लिप ऑपरेशन डीबग करा"</string> <string name="track_frame_time" msgid="6094365083096851167">"प्रोफाइल HWUI रेंडरिंग"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"GPU डीबग स्तर सुरू करा"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"डीबग अॅप्ससाठी GPU डीबग स्तर लोड करण्याची अनुमती द्या"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"डीबग अॅप्ससाठी GPU डीबग स्तर लोड करण्याची अनुमती द्या"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"विंडो अॅनिमेशन स्केल"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"ट्रांझिशन अॅनिमेशन स्केल"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"अॅनिमेटर कालावधी स्केल"</string> @@ -330,7 +330,7 @@ <string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यवर अॅप्सना अनुमती देण्याची सक्ती करा"</string> <string name="force_allow_on_external_summary" msgid="3640752408258034689">"manifest मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य स्टोरेजवर लेखन केले जाण्यासाठी पात्र बनविते"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"अॅक्टिव्हिटीचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string> - <string name="force_resizable_activities_summary" msgid="6667493494706124459">"manifest मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा."</string> + <string name="force_resizable_activities_summary" msgid="6667493494706124459">"manifest मूल्यांकडे दुर्लक्ष करून, एकाहून अधिक-विंडोसाठी सर्व अॅक्टिव्हिटींचा आकार बदलण्यायोग्य करा."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सुरू करा"</string> <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सुरू करा."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप पासवर्ड"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index dfb99f549cd1..1baa60961c34 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -376,10 +376,10 @@ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Deze functie is experimenteel en kan invloed hebben op de prestaties."</string> <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4845022416859002011">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> - <string name="power_remaining_duration_only" msgid="6123167166221295462">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend"</string> - <string name="power_discharging_duration" msgid="8848256785736335185">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_remaining_duration_only_enhanced" msgid="4189311599812296592">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend op basis van je gebruik"</string> - <string name="power_discharging_duration_enhanced" msgid="1992003260664804080">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend op basis van je gebruik (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_remaining_duration_only" msgid="6123167166221295462">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> + <string name="power_discharging_duration" msgid="8848256785736335185">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_remaining_duration_only_enhanced" msgid="4189311599812296592">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> op basis van je gebruik"</string> + <string name="power_discharging_duration_enhanced" msgid="1992003260664804080">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> op basis van je gebruik (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <!-- no translation found for power_remaining_duration_only_short (9183070574408359726) --> <skip /> <string name="power_discharge_by_enhanced" msgid="2095821536747992464">"Is nog genoeg tot ongeveer <xliff:g id="TIME">%1$s</xliff:g> op basis van je gebruik (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -388,10 +388,10 @@ <string name="power_discharge_by_only" msgid="107616694963545745">"Is nog genoeg tot ongeveer <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Tot <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_extend_battery" msgid="4401408879069551485">"Batterijduur verlengen tot na <xliff:g id="TIME">%1$s</xliff:g>"</string> - <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Minder dan <xliff:g id="THRESHOLD">%1$s</xliff:g> resterend"</string> - <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Minder dan <xliff:g id="THRESHOLD">%1$s</xliff:g> resterend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Meer dan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_remaining_only_more_than_subtext" msgid="8931654680569617380">"Meer dan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend"</string> + <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Nog minder dan <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> + <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Nog minder dan <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Nog meer dan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_remaining_only_more_than_subtext" msgid="8931654680569617380">"Nog meer dan <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="1181059207608751924">"Telefoon wordt binnenkort mogelijk uitgeschakeld"</string> <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="2606370266981054691">"Tablet wordt binnenkort mogelijk uitgeschakeld"</string> <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="2918084807716859985">"Apparaat wordt binnenkort mogelijk uitgeschakeld"</string> @@ -419,7 +419,7 @@ <item msgid="1286113608943010849">"100%"</item> </string-array> <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> geleden"</string> - <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> resterend"</string> + <string name="remaining_length_format" msgid="7886337596669190587">"Nog <xliff:g id="ID_1">%1$s</xliff:g>"</string> <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Klein"</string> <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standaard"</string> <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Groot"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 3ec90b2e3e26..f64d8fc5aa76 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -215,14 +215,14 @@ <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"ਚਿਤਾਵਨੀ: ਡੀਵਾਈਸ ਸੁਰੱਖਿਆ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਉਦੋਂ ਇਸ ਡੀਵਾਈਸ ਤੇ ਕੰਮ ਨਹੀਂ ਕਰਨਗੀਆਂ ਜਦੋਂ ਇਹ ਸੈਟਿੰਗ ਚਾਲੂ ਹੋਵੇਗੀ।"</string> <string name="mock_location_app" msgid="7966220972812881854">"ਮੌਕ ਟਿਕਾਣੇ ਵਾਲੀ ਐਪ ਚੁਣੋ"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"ਕੋਈ ਵੀ ਮੌਕ ਟਿਕਾਣੇ ਵਾਲੀ ਐਪ ਸੈੱਟ ਨਹੀਂ ਹੈ"</string> - <string name="mock_location_app_set" msgid="8966420655295102685">"ਮੌਕ ਸਥਾਨ ਐਪ: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="mock_location_app_set" msgid="8966420655295102685">"ਮੌਕ ਟਿਕਾਣਾ ਐਪ: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"ਨੈੱਟਵਰਕਿੰਗ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"ਵਾਈ-ਫਾਈ ਵਰਬੋਸ ਲੌਗਿੰਗ ਚਾਲੂ ਕਰੋ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"ਮੋਬਾਈਲ ਡਾਟਾ ਹਮੇਸ਼ਾਂ ਕਿਰਿਆਸ਼ੀਲ"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ਟੈਦਰਿੰਗ ਹਾਰਡਵੇਅਰ ਐਕਸੈੱਲਰੇਸ਼ਨ"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string> - <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ਪੂਰਨ ਅਵਾਜ਼ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string> + <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ਪੂਰਨ ਅਵਾਜ਼ ਨੂੰ ਬੰਦ ਕਰੋ"</string> <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ"</string> <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ ਚੁਣੋ"</string> <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ਬਲੂਟੁੱਥ ਆਡੀਓ ਕੋਡੇਕ"</string> @@ -251,7 +251,7 @@ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ ਲੌਗਰ ਆਕਾਰ ਚੁਣੋ"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"ਕੀ ਲੌਗਰ ਪ੍ਰਸਿੱਸਟੈਂਟ ਸਟੋਰੇਜ ਨੂੰ ਸਾਫ਼ ਕਰਨਾ ਹੈ?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"ਜਦੋਂ ਅਸੀਂ ਪ੍ਰਸਿੱਸਟੈਂਟ ਲੌਗਰ ਨਾਲ ਨਿਗਰਾਨੀ ਨਹੀਂ ਕਰ ਰਹੇ ਹੁੰਦੇ ਹਾਂ, ਤਾਂ ਸਾਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਵਿੱਚ ਮੌਜੂਦ ਲੌਗਰ ਡਾਟੇ ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਲੋੜ ਪੈਂਦੀ ਹੈ।"</string> - <string name="select_logpersist_title" msgid="7530031344550073166">"ਡੀਵਾਈਸ \'ਤੇ ਲੌਗ ਬਫ਼ਰਾਂ ਨੂੰ ਸਥਾਈ ਤੌਰ \'ਤੇ ਸਟੋਰ ਕਰੋ"</string> + <string name="select_logpersist_title" msgid="7530031344550073166">"ਡੀਵਾਈਸ \'ਤੇ ਲੌਗਰ ਡਾਟਾ ਨੂੰ ਸਥਾਈ ਤੌਰ \'ਤੇ ਸਟੋਰ ਕਰੋ"</string> <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਈ ਤੌਰ \'ਤੇ ਸਟੋਰ ਕਰਨ ਲਈ ਲੌਗ ਬਫ਼ਰਾਂ ਨੂੰ ਚੁਣੋ"</string> <string name="select_usb_configuration_title" msgid="2649938511506971843">"USB ਕੌਂਫਿਗਰੇਸ਼ਨ ਚੁਣੋ"</string> <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"USB ਕੌਂਫਿਗਰੇਸ਼ਨ ਚੁਣੋ"</string> @@ -268,7 +268,7 @@ <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB \'ਤੇ ਐਪਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string> <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ਹਾਨੀਕਾਰਕ ਵਿਵਹਾਰ ਲਈ ADB/ADT ਰਾਹੀਂ ਸਥਾਪਤ ਕੀਤੀਆਂ ਐਪਾਂ ਦੀ ਜਾਂਚ ਕਰੋ।"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਈਆਂ ਜਾਣਗੀਆਂ (ਸਿਰਫ਼ MAC ਪਤੇ)"</string> - <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ਰਿਮੋਟ ਡੀਵਾਈਸਾਂ ਨਾਲ ਅਵਾਜ਼ੀ ਸਮੱਸਿਆਵਾਂ ਜਿਵੇਂ ਕਿ ਨਾ ਪਸੰਦ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਉੱਚੀ ਅਵਾਜ਼ ਜਾਂ ਕੰਟਰੋਲ ਦੀ ਕਮੀ ਵਰਗੀ ਹਾਲਤ ਵਿੱਚ ਬਲੂਟੁੱਥ ਪੂਰਨ ਅਵਾਜ਼ਮ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ।"</string> + <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ਰਿਮੋਟ ਡੀਵਾਈਸਾਂ ਨਾਲ ਅਵਾਜ਼ੀ ਸਮੱਸਿਆਵਾਂ ਜਿਵੇਂ ਕਿ ਨਾ ਪਸੰਦ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਉੱਚੀ ਅਵਾਜ਼ ਜਾਂ ਕੰਟਰੋਲ ਦੀ ਕਮੀ ਵਰਗੀ ਹਾਲਤ ਵਿੱਚ ਬਲੂਟੁੱਥ ਪੂਰਨ ਅਵਾਜ਼ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ।"</string> <string name="enable_terminal_title" msgid="95572094356054120">"ਸਥਾਨਕ ਟਰਮੀਨਲ"</string> <string name="enable_terminal_summary" msgid="67667852659359206">"ਟਰਮੀਨਲ ਐਪ ਨੂੰ ਚਾਲੂ ਕਰੋ ਜੋ ਸਥਾਨਕ ਸ਼ੈਲ ਪਹੁੰਚ ਪੇਸ਼ਕਸ਼ ਕਰਦਾ ਹੈ"</string> <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ਜਾਂਚ"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml index 9e7d040e746b..855be6f3d2df 100644 --- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml +++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml @@ -59,7 +59,7 @@ <item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> - <item msgid="3966341281672645384">"Desativada"</item> + <item msgid="3966341281672645384">"Desativado"</item> <item msgid="1969681323976948639">"Filtro ativado"</item> <item msgid="8719029132154020716">"Ativada"</item> </string-array> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index ffaed3737ee9..395aee9df117 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -158,7 +158,7 @@ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom de voz"</string> <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string> <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string> - <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string> + <string name="tts_lang_use_system" msgid="2679252467416513208">"Usa o idioma do sistema"</string> <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string> <string name="tts_default_lang_summary" msgid="5219362163902707785">"Define a voz específica do idioma para o texto falado"</string> <string name="tts_play_example_title" msgid="7094780383253097230">"Ouça um exemplo"</string> @@ -218,7 +218,7 @@ <string name="mock_location_app_set" msgid="8966420655295102685">"App de local fictício: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificação de Display sem fio"</string> - <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ativar registro extenso de Wi-Fi"</string> + <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ativar registro detalhado de Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sem nomes"</string> @@ -244,7 +244,7 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string> <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Não foi possível conectar"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string> - <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string> + <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string> <string name="wifi_metered_label" msgid="4514924227256839725">"Limitada"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Ilimitada"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamanhos de buffer de logger"</string> @@ -257,8 +257,8 @@ <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Selecionar configuração USB"</string> <string name="allow_mock_location" msgid="2787962564578664888">"Permitir locais fictícios"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Permitir locais fictícios"</string> - <string name="debug_view_attributes" msgid="6485448367803310384">"Ativar visualiz. insp. atributo"</string> - <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Sempre manter dados móveis ativos, mesmo quando o Wi-Fi estiver ativado (para troca rápida de rede)."</string> + <string name="debug_view_attributes" msgid="6485448367803310384">"Ativar visualização de inspeção de atributo"</string> + <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Sempre manter dados móveis ativos, mesmo quando o Wi-Fi estiver ativado (para troca rápida de rede)"</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Usar aceleração de hardware de tethering quando disponível"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Permitir a depuração USB?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"A depuração USB serve apenas para fins de desenvolvimento. Use-a para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> @@ -266,7 +266,7 @@ <string name="dev_settings_warning_title" msgid="7244607768088540165">"Ativar as configurações de desenvolvimento?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Dispositivos Bluetooth sem nomes (somente endereços MAC) serão exibidos"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string> <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string> @@ -280,15 +280,15 @@ <string name="select_application" msgid="5156029161289091703">"Selecionar app"</string> <string name="no_application" msgid="2813387563129153880">"Nada"</string> <string name="wait_for_debugger" msgid="1202370874528893091">"Aguardar depurador"</string> - <string name="wait_for_debugger_summary" msgid="1766918303462746804">"App depurado espera conexão com debugger antes de ser executado."</string> + <string name="wait_for_debugger_summary" msgid="1766918303462746804">"O app depurado espera a conexão com o depurador para ser executado"</string> <string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string> <string name="debug_drawing_category" msgid="6755716469267367852">"Desenho"</string> <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Renderização acelerada por hardware"</string> <string name="media_category" msgid="4388305075496848353">"Mídia"</string> <string name="debug_monitoring_category" msgid="7640508148375798343">"Monitoramento"</string> - <string name="strict_mode" msgid="1938795874357830695">"Modo rigoroso ativado"</string> + <string name="strict_mode" msgid="1938795874357830695">"Modo restrito ativado"</string> <string name="strict_mode_summary" msgid="142834318897332338">"Piscar tela se apps demorarem no processo principal"</string> - <string name="pointer_location" msgid="6084434787496938001">"Localização do ponteiro"</string> + <string name="pointer_location" msgid="6084434787496938001">"Localização do cursor"</string> <string name="pointer_location_summary" msgid="840819275172753713">"Exibir dados de toque"</string> <string name="show_touches" msgid="2642976305235070316">"Mostrar toques"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Mostrar feedback visual para toques"</string> @@ -307,16 +307,16 @@ <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Desativar roteam. autom. p/ perif. de áudio USB"</string> <string name="debug_layout" msgid="5981361776594526155">"Mostrar limites de layout"</string> <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string> - <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string> - <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as localidades"</string> + <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar layout da direita p/ esquerda"</string> + <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar a direção do layout da direita para a esquerda para todas as localidades"</string> <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string> <string name="force_msaa_summary" msgid="9123553203895817537">"Ativar 4x MSAA em apps OpenGL ES 2.0"</string> <string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operações de corte não retangulares"</string> <string name="track_frame_time" msgid="6094365083096851167">"Classific. render. HWUI"</string> - <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ativar camadas depuração de GPU"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. camadas de depuração GPU p/ apps de dep."</string> - <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de anim. da janela"</string> - <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala anim. de transição"</string> + <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ativar camadas de depuração de GPU"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. de camadas de depuração de GPU p/ apps de dep"</string> + <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de animação da janela"</string> + <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala de animação de transição"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de duração do Animator"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simular telas secundárias"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Apps"</string> @@ -326,9 +326,9 @@ <string name="show_all_anrs" msgid="4924885492787069007">"Mostrar ANRs em 2º plano"</string> <string name="show_all_anrs_summary" msgid="6636514318275139826">"Exibir a caixa de diálogo \"App não responde\" para apps em segundo plano"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostrar avisos do canal de notif."</string> - <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Exibe aviso na tela quando um app posta notificação sem canal válido"</string> + <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Exibir aviso na tela quando um app posta notificação sem canal válido"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Qualifica apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Qualificar apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string> <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string> @@ -431,7 +431,7 @@ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Próxima"</string> <string name="retail_demo_reset_title" msgid="696589204029930100">"Senha necessária"</string> <string name="active_input_method_subtypes" msgid="3596398805424733238">"Métodos ativos de entrada"</string> - <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Usar idiomas do sistema"</string> + <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Usa idiomas do sistema"</string> <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Falha ao abrir as configurações de <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string> <string name="ime_security_warning" msgid="4135828934735934248">"Este método de entrada pode coletar todo o texto que você digita, incluindo dados pessoais, como senhas e números de cartão de crédito. É um método do app <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Usar este método de entrada?"</string> <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"Observação: após uma reinicialização, não é possível iniciar este app até que você desbloqueie seu smartphone"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index aaa6a027ef6f..34f8e7dd9c9b 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -251,7 +251,7 @@ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Selec. tam. reg. p/ mem. int. reg."</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Pretende limpar o armazenamento persistente do registo?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Quando deixamos de monitorizar com o registo persistente, é necessário apagar os dados de registo que se encontram no seu dispositivo."</string> - <string name="select_logpersist_title" msgid="7530031344550073166">"Arm. dados de registo persist. no disp."</string> + <string name="select_logpersist_title" msgid="7530031344550073166">"Guardar dados de registo consistentemente"</string> <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Selecionar buffers de registo para armazenamento persistente no dispositivo"</string> <string name="select_usb_configuration_title" msgid="2649938511506971843">"Selecionar configuração USB"</string> <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Selecionar configuração USB"</string> @@ -294,7 +294,7 @@ <string name="show_touches_summary" msgid="6101183132903926324">"Mostrar feedback visual para toques"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Atualiz. de superfície"</string> <string name="show_screen_updates_summary" msgid="2569622766672785529">"Destacar a superfície da janela ao atualizar"</string> - <string name="show_hw_screen_updates" msgid="4117270979975470789">"Most. atualiz. de vistas"</string> + <string name="show_hw_screen_updates" msgid="4117270979975470789">"Ver atualizações de vistas"</string> <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Destacar vistas em janelas quando desenhadas"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Mostrar atual. cam. hard."</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Camadas de hard. flash verdes quando estão atuali."</string> @@ -303,11 +303,11 @@ <string name="disable_overlays_summary" msgid="3578941133710758592">"Utilizar sempre GPU para a composição do ecrã"</string> <string name="simulate_color_space" msgid="6745847141353345872">"Simular espaço da cor"</string> <string name="enable_opengl_traces_title" msgid="6790444011053219871">"Ativar vestígios OpenGL"</string> - <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Desativ. encam. áudio USB"</string> + <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Desativar encaminhamento áudio USB"</string> <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Desativar encam. auto. para periféricos áudio USB"</string> <string name="debug_layout" msgid="5981361776594526155">"Mostrar limit. do esquema"</string> <string name="debug_layout_summary" msgid="2001775315258637682">"Apresentar limites de clipes, margens, etc."</string> - <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. do esq. RTL"</string> + <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar direção do esquema RTL"</string> <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar dir. do esq. do ecrã p. RTL tds os locais"</string> <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string> <string name="force_msaa_summary" msgid="9123553203895817537">"Ativar o 4x MSAA em aplicações OpenGL ES 2.0"</string> @@ -317,7 +317,7 @@ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. cam. depuração GPU p/ dep. app"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de anim. da janela"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala de anim. de trans."</string> - <string name="animator_duration_scale_title" msgid="3406722410819934083">"Esc. de duração do anim."</string> + <string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de duração de animação"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simular apresentações secundárias"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Aplicações"</string> <string name="immediately_destroy_activities" msgid="1579659389568133959">"Não manter atividades"</string> diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml index 9e7d040e746b..855be6f3d2df 100644 --- a/packages/SettingsLib/res/values-pt/arrays.xml +++ b/packages/SettingsLib/res/values-pt/arrays.xml @@ -59,7 +59,7 @@ <item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> - <item msgid="3966341281672645384">"Desativada"</item> + <item msgid="3966341281672645384">"Desativado"</item> <item msgid="1969681323976948639">"Filtro ativado"</item> <item msgid="8719029132154020716">"Ativada"</item> </string-array> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index ffaed3737ee9..395aee9df117 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -158,7 +158,7 @@ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom de voz"</string> <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string> <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string> - <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string> + <string name="tts_lang_use_system" msgid="2679252467416513208">"Usa o idioma do sistema"</string> <string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string> <string name="tts_default_lang_summary" msgid="5219362163902707785">"Define a voz específica do idioma para o texto falado"</string> <string name="tts_play_example_title" msgid="7094780383253097230">"Ouça um exemplo"</string> @@ -218,7 +218,7 @@ <string name="mock_location_app_set" msgid="8966420655295102685">"App de local fictício: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificação de Display sem fio"</string> - <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ativar registro extenso de Wi-Fi"</string> + <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ativar registro detalhado de Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sem nomes"</string> @@ -244,7 +244,7 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string> <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Não foi possível conectar"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string> - <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string> + <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string> <string name="wifi_metered_label" msgid="4514924227256839725">"Limitada"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Ilimitada"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamanhos de buffer de logger"</string> @@ -257,8 +257,8 @@ <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Selecionar configuração USB"</string> <string name="allow_mock_location" msgid="2787962564578664888">"Permitir locais fictícios"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Permitir locais fictícios"</string> - <string name="debug_view_attributes" msgid="6485448367803310384">"Ativar visualiz. insp. atributo"</string> - <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Sempre manter dados móveis ativos, mesmo quando o Wi-Fi estiver ativado (para troca rápida de rede)."</string> + <string name="debug_view_attributes" msgid="6485448367803310384">"Ativar visualização de inspeção de atributo"</string> + <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Sempre manter dados móveis ativos, mesmo quando o Wi-Fi estiver ativado (para troca rápida de rede)"</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Usar aceleração de hardware de tethering quando disponível"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Permitir a depuração USB?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"A depuração USB serve apenas para fins de desenvolvimento. Use-a para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> @@ -266,7 +266,7 @@ <string name="dev_settings_warning_title" msgid="7244607768088540165">"Ativar as configurações de desenvolvimento?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string> <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Dispositivos Bluetooth sem nomes (somente endereços MAC) serão exibidos"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string> <string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string> @@ -280,15 +280,15 @@ <string name="select_application" msgid="5156029161289091703">"Selecionar app"</string> <string name="no_application" msgid="2813387563129153880">"Nada"</string> <string name="wait_for_debugger" msgid="1202370874528893091">"Aguardar depurador"</string> - <string name="wait_for_debugger_summary" msgid="1766918303462746804">"App depurado espera conexão com debugger antes de ser executado."</string> + <string name="wait_for_debugger_summary" msgid="1766918303462746804">"O app depurado espera a conexão com o depurador para ser executado"</string> <string name="debug_input_category" msgid="1811069939601180246">"Entrada"</string> <string name="debug_drawing_category" msgid="6755716469267367852">"Desenho"</string> <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Renderização acelerada por hardware"</string> <string name="media_category" msgid="4388305075496848353">"Mídia"</string> <string name="debug_monitoring_category" msgid="7640508148375798343">"Monitoramento"</string> - <string name="strict_mode" msgid="1938795874357830695">"Modo rigoroso ativado"</string> + <string name="strict_mode" msgid="1938795874357830695">"Modo restrito ativado"</string> <string name="strict_mode_summary" msgid="142834318897332338">"Piscar tela se apps demorarem no processo principal"</string> - <string name="pointer_location" msgid="6084434787496938001">"Localização do ponteiro"</string> + <string name="pointer_location" msgid="6084434787496938001">"Localização do cursor"</string> <string name="pointer_location_summary" msgid="840819275172753713">"Exibir dados de toque"</string> <string name="show_touches" msgid="2642976305235070316">"Mostrar toques"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Mostrar feedback visual para toques"</string> @@ -307,16 +307,16 @@ <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Desativar roteam. autom. p/ perif. de áudio USB"</string> <string name="debug_layout" msgid="5981361776594526155">"Mostrar limites de layout"</string> <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string> - <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string> - <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as localidades"</string> + <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar layout da direita p/ esquerda"</string> + <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar a direção do layout da direita para a esquerda para todas as localidades"</string> <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string> <string name="force_msaa_summary" msgid="9123553203895817537">"Ativar 4x MSAA em apps OpenGL ES 2.0"</string> <string name="show_non_rect_clip" msgid="505954950474595172">"Depurar operações de corte não retangulares"</string> <string name="track_frame_time" msgid="6094365083096851167">"Classific. render. HWUI"</string> - <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ativar camadas depuração de GPU"</string> - <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. camadas de depuração GPU p/ apps de dep."</string> - <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de anim. da janela"</string> - <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala anim. de transição"</string> + <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Ativar camadas de depuração de GPU"</string> + <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Permitir carreg. de camadas de depuração de GPU p/ apps de dep"</string> + <string name="window_animation_scale_title" msgid="6162587588166114700">"Escala de animação da janela"</string> + <string name="transition_animation_scale_title" msgid="387527540523595875">"Escala de animação de transição"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Escala de duração do Animator"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simular telas secundárias"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Apps"</string> @@ -326,9 +326,9 @@ <string name="show_all_anrs" msgid="4924885492787069007">"Mostrar ANRs em 2º plano"</string> <string name="show_all_anrs_summary" msgid="6636514318275139826">"Exibir a caixa de diálogo \"App não responde\" para apps em segundo plano"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostrar avisos do canal de notif."</string> - <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Exibe aviso na tela quando um app posta notificação sem canal válido"</string> + <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Exibir aviso na tela quando um app posta notificação sem canal válido"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Qualifica apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Qualificar apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string> <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string> @@ -431,7 +431,7 @@ <string name="retail_demo_reset_next" msgid="8356731459226304963">"Próxima"</string> <string name="retail_demo_reset_title" msgid="696589204029930100">"Senha necessária"</string> <string name="active_input_method_subtypes" msgid="3596398805424733238">"Métodos ativos de entrada"</string> - <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Usar idiomas do sistema"</string> + <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Usa idiomas do sistema"</string> <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Falha ao abrir as configurações de <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string> <string name="ime_security_warning" msgid="4135828934735934248">"Este método de entrada pode coletar todo o texto que você digita, incluindo dados pessoais, como senhas e números de cartão de crédito. É um método do app <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Usar este método de entrada?"</string> <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"Observação: após uma reinicialização, não é possível iniciar este app até que você desbloqueie seu smartphone"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 4b3ec9941744..ec62c1dd88dc 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -293,7 +293,7 @@ <string name="show_touches" msgid="2642976305235070316">"Afișați atingerile"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Afișați feedbackul vizual pentru atingeri"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Actualizări suprafețe"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Iluminare suprafețe toată fereastra la actualizare"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Iluminarea întregii fereastre la actualizare"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Afiș. actualizări ecran"</string> <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Iluminare ecrane din ferestre la desenare"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Actualiz. strat. hardware"</string> @@ -326,9 +326,9 @@ <string name="show_all_anrs" msgid="4924885492787069007">"Afișați ANR de fundal"</string> <string name="show_all_anrs_summary" msgid="6636514318275139826">"Afișați dialogul Aplicația nu răspunde pentru aplicațiile din fundal"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Afișați avertismentele de pe canalul de notificări"</string> - <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Afișează avertisment pe ecran când o aplicație postează o notificare fără canal valid"</string> + <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Afișați avertisment pe ecran când o aplicație postează o notificare fără canal valid"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Forțați accesul aplicațiilor la stocarea externă"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Face ca orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Faceți ca orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string> <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permiteți redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Activați ferestrele cu formă liberă"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 4943a82e4b85..55ac00dd579d 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -288,9 +288,9 @@ <string name="debug_monitoring_category" msgid="7640508148375798343">"Мониторинг"</string> <string name="strict_mode" msgid="1938795874357830695">"Строгий режим"</string> <string name="strict_mode_summary" msgid="142834318897332338">"Подсвечивать экран во время длительных операций"</string> - <string name="pointer_location" msgid="6084434787496938001">"Отображать касания"</string> - <string name="pointer_location_summary" msgid="840819275172753713">"Визуализировать на экране нажатия и жесты"</string> - <string name="show_touches" msgid="2642976305235070316">"Визуальный отклик"</string> + <string name="pointer_location" msgid="6084434787496938001">"Место нажатия"</string> + <string name="pointer_location_summary" msgid="840819275172753713">"Показывать данные нажатий и жестов"</string> + <string name="show_touches" msgid="2642976305235070316">"Показывать нажатия"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Показывать места нажатия на экране"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Показ. обнов. поверхности"</string> <string name="show_screen_updates_summary" msgid="2569622766672785529">"Подсвечивать поверхности окон при обновлении"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index f3a28f171413..fff2d9dfb80c 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -152,7 +152,7 @@ <string name="launch_defaults_some" msgid="313159469856372621">"Nastavljene so nekatere privzete nastavitve"</string> <string name="launch_defaults_none" msgid="4241129108140034876">"Ni privzetih nastavitev"</string> <string name="tts_settings" msgid="8186971894801348327">"Nastavitve pretvorbe besedila v govor"</string> - <string name="tts_settings_title" msgid="1237820681016639683">"Besedilo v govor"</string> + <string name="tts_settings_title" msgid="1237820681016639683">"Pretvorba besedila v govor"</string> <string name="tts_default_rate_title" msgid="6030550998379310088">"Hitrost govora"</string> <string name="tts_default_rate_summary" msgid="4061815292287182801">"Hitrost govorjenega besedila"</string> <string name="tts_default_pitch_title" msgid="6135942113172488671">"Višina tona"</string> @@ -205,8 +205,8 @@ <string name="clear_adb_keys" msgid="4038889221503122743">"Preklic dovoljenj za odpr. težav prek USB"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"Bližnjica za por. o napakah"</string> <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Prikaz gumba za ustvarjanje poročila o napakah v meniju za vklop/izklop"</string> - <string name="keep_screen_on" msgid="1146389631208760344">"Brez zaklepanja"</string> - <string name="keep_screen_on_summary" msgid="2173114350754293009">"Med polnjenjem se zaslon ne bo nikoli zaklenil"</string> + <string name="keep_screen_on" msgid="1146389631208760344">"Brez izklopa zaslona"</string> + <string name="keep_screen_on_summary" msgid="2173114350754293009">"Med polnjenjem se zaslon ne bo nikoli izklopil"</string> <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Omogoči zajem dnevnika Bluetooth HCI"</string> <string name="bt_hci_snoop_log_summary" msgid="8857606786588106495">"Zajemanje paketov Bluetooth. (po spremembi te nastavitve preklopite Bluetooth)"</string> <string name="oem_unlock_enable" msgid="6040763321967327691">"Odklepanje OEM"</string> @@ -215,21 +215,21 @@ <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"OPOZORILO: Ko je vklopljena ta nastavitev, funkcije za zaščito naprave v tej napravi ne bodo delovale."</string> <string name="mock_location_app" msgid="7966220972812881854">"Izberite aplikacijo za simulirano lokacijo"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"Aplikacija za simulirano lokacijo ni nastavljena"</string> - <string name="mock_location_app_set" msgid="8966420655295102685">"Aplikacija za lažno lokacijo: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="mock_location_app_set" msgid="8966420655295102685">"Aplikacija za simulirano lokacijo: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Omrežja"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Potrdilo brezžičnega zaslona"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogoči podrob. zapis. dnevnika za Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Prenos podatkov v mobilnem omrežju je vedno aktiven"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Prikaži naprave Bluetooth brez imen"</string> - <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogočanje absolutnega praga glasnosti"</string> + <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogočanje absolutne glasnosti"</string> <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Različica profila AVRCP za Bluetooth"</string> <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Izberite različico profila AVRCP za Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Zvočni kodek za Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="8436224899475822557">"Sproži zvočni kodek za Bluetooth\nIzbor"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Hitrost vzorčenja zvoka prek Bluetootha"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="8010380028880963535">"Sproži zvočni kodek za Bluetooth\nIzbor: hitrost vzorčenja"</string> - <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Število bitov na vzorec za zvok prek Bluetootha"</string> + <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bitov na vzorec za zvok prek Bluetootha"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="8063859754619484760">"Sproži zvočni kodek za Bluetooth\nIzbor: število bitov na vzorec"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način zvočnega kanala prek Bluetootha"</string> <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="7234956835280563341">"Sproži zvočni kodek za Bluetooth\nIzbor: način kanala"</string> @@ -251,7 +251,7 @@ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Izberite velikost medpomnilnika dnevnika"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Želite izbrisati trajno shranjevanje dnevniškega orodja?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Ko prenehamo spremljanje s trajnim dnevniškim orodjem, moramo podatke tega orodja, shranjene v napravi, izbrisati."</string> - <string name="select_logpersist_title" msgid="7530031344550073166">"Trajno shranjevanje podatkov dnevniškega orodja v napravi"</string> + <string name="select_logpersist_title" msgid="7530031344550073166">"Trajno shranjevanje dnevnika v napravi"</string> <string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Izberite, katere medpomnilnike dnevnika želite trajno shraniti v napravi"</string> <string name="select_usb_configuration_title" msgid="2649938511506971843">"Izbira konfiguracije USB"</string> <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Izbira konfiguracije USB"</string> @@ -268,7 +268,7 @@ <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Preveri aplikacije prek USB"</string> <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Preveri, ali so aplikacije, nameščene prek ADB/ADT, škodljive."</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"Prikazane bodo naprave Bluetooth brez imen (samo z naslovi MAC)"</string> - <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogoči funkcijo absolutnega praga glasnosti za Bluetooth, če pride do težav z glasnostjo z oddaljenimi napravami, kot je nesprejemljivo visoka glasnost ali pomanjkanje nadzora."</string> + <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogoči funkcijo absolutne glasnosti za Bluetooth, če pride do težav z glasnostjo z oddaljenimi napravami, kot je nesprejemljivo visoka glasnost ali pomanjkanje nadzora."</string> <string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string> <string name="enable_terminal_summary" msgid="67667852659359206">"Omogočanje terminalske aplikacije za dostop do lokalne lupine"</string> <string name="hdcp_checking_title" msgid="8605478913544273282">"Preverjanje HDCP"</string> @@ -279,7 +279,7 @@ <string name="debug_app_set" msgid="2063077997870280017">"Aplikacija za iskanje napak: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="select_application" msgid="5156029161289091703">"Izberite aplikacijo"</string> <string name="no_application" msgid="2813387563129153880">"Nič"</string> - <string name="wait_for_debugger" msgid="1202370874528893091">"Počakajte na iskalnik napak"</string> + <string name="wait_for_debugger" msgid="1202370874528893091">"Počakaj na iskalnik napak"</string> <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacija, v kateri iščete napako, pred izvajanjem čaka na povezavo z iskalnikom napak"</string> <string name="debug_input_category" msgid="1811069939601180246">"Vnos"</string> <string name="debug_drawing_category" msgid="6755716469267367852">"Risanje"</string> @@ -289,13 +289,13 @@ <string name="strict_mode" msgid="1938795874357830695">"Strog način je omogočen"</string> <string name="strict_mode_summary" msgid="142834318897332338">"Osveži zaslon pri dolgih postopkih v glavni niti"</string> <string name="pointer_location" msgid="6084434787496938001">"Mesto kazalca"</string> - <string name="pointer_location_summary" msgid="840819275172753713">"Prekriv. zaslona prikazuje tren. podatke za dotik"</string> + <string name="pointer_location_summary" msgid="840819275172753713">"Prekriv. zaslona prikazuje trenutni dotik"</string> <string name="show_touches" msgid="2642976305235070316">"Prikaz dotikov"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Prikaz vizualnih povratnih informacij za dotike"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Pokaži posodob. površine"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"Ob posodobitvi osvetli celotne površine oken"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"Ob posodobitvi osveži celotne površine oken"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"Prikaži posodob. pogleda"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Osvetli poglede v oknih pri risanju"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"Osveži poglede v oknih pri risanju"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"Pokaži pos. sl. str. opr."</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Obarvaj sloje strojne opreme zeleno ob posodobitvi"</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"Prekoračitev območja GPE"</string> @@ -317,7 +317,7 @@ <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Apl. za odpr. nap. dovoli nal. sloj. odpr. nap. GPE"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Merilo animacije okna"</string> <string name="transition_animation_scale_title" msgid="387527540523595875">"Merilo animacije prehoda"</string> - <string name="animator_duration_scale_title" msgid="3406722410819934083">"Lestvica trajanja animacije"</string> + <string name="animator_duration_scale_title" msgid="3406722410819934083">"Merilo trajanja animacije"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simul. sekund. prikazov."</string> <string name="debug_applications_category" msgid="4206913653849771549">"Aplikacije"</string> <string name="immediately_destroy_activities" msgid="1579659389568133959">"Ne obdrži dejavnosti"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 38b16936947a..36734468e391 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -213,7 +213,7 @@ <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Дозволи откључавање функције за покретање"</string> <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"Желите ли да дозволите откључавање произвођача оригиналне опреме (OEM)?"</string> <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"УПОЗОРЕЊЕ: Функције за заштиту уређаја неће функционисати на овом уређају док је ово подешавање укључено."</string> - <string name="mock_location_app" msgid="7966220972812881854">"Изабери апликацију за лажну локацију"</string> + <string name="mock_location_app" msgid="7966220972812881854">"Изаберите апликацију за лажну локацију"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"Апликација за лажну локацију није подешена"</string> <string name="mock_location_app_set" msgid="8966420655295102685">"Апликација за лажну локацију: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="7044075693643009662">"Умрежавање"</string> @@ -289,7 +289,7 @@ <string name="strict_mode" msgid="1938795874357830695">"Омогућен је строги режим"</string> <string name="strict_mode_summary" msgid="142834318897332338">"Нека екран трепери када апликације обављају дуге операције на главној нити"</string> <string name="pointer_location" msgid="6084434787496938001">"Локација показивача"</string> - <string name="pointer_location_summary" msgid="840819275172753713">"Постав. елемент са тренутним подацима о додиру"</string> + <string name="pointer_location_summary" msgid="840819275172753713">"Преклопни елемент са тренутним подацима о додиру"</string> <string name="show_touches" msgid="2642976305235070316">"Приказуј додире"</string> <string name="show_touches_summary" msgid="6101183132903926324">"Приказуј визуелне повратне информације за додире"</string> <string name="show_screen_updates" msgid="5470814345876056420">"Прикажи ажурирања површине"</string> @@ -311,8 +311,8 @@ <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Наметни смер распореда екрана здесна налево за све локалитете"</string> <string name="force_msaa" msgid="7920323238677284387">"Наметни 4x MSAA"</string> <string name="force_msaa_summary" msgid="9123553203895817537">"Омогући 4x MSAA у OpenGL ES 2.0 апликацијама"</string> - <string name="show_non_rect_clip" msgid="505954950474595172">"Отклони грешке у вези са радњама за исецање области које нису правоугаоног облика"</string> - <string name="track_frame_time" msgid="6094365083096851167">"Прик. проф. помоћу HWUI-а"</string> + <string name="show_non_rect_clip" msgid="505954950474595172">"Отклони грешке исецања области које нису правоугаоног облика"</string> + <string name="track_frame_time" msgid="6094365083096851167">"Пендеруј помоћу HWUI-а"</string> <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Омогући слојеве за отклањање грешака GPU-a"</string> <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Омогући учитавање отк. греш. GPU-a у апл. за отк. греш."</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Размера анимације прозора"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 3960f4428d57..48bcbd47b2a4 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -42,8 +42,7 @@ <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s வழியாகக் கிடைக்கிறது"</string> <string name="tap_to_sign_up" msgid="6449724763052579434">"பதிவு செய்யத் தட்டவும்"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"இணைக்கப்பட்டுள்ளது, ஆனால் இண்டர்நெட் இல்லை"</string> - <!-- no translation found for wifi_limited_connection (7717855024753201527) --> - <skip /> + <string name="wifi_limited_connection" msgid="7717855024753201527">"வரம்பிற்கு உட்பட்ட இணைப்பு"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"இணைய இணைப்பு இல்லை"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"உள்நுழைய வேண்டும்"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"தற்காலிகமாக அணுகல் புள்ளி நிரம்பியுள்ளது"</string> @@ -75,11 +74,9 @@ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"இணைக்கப்பட்டது (மீடியா இல்லை), பேட்டரி <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"இணைக்கப்பட்டது (மொபைல் அல்லது மீடியா இல்லை), பேட்டரி <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_active_battery_level" msgid="3149689299296462009">"செயலில் உள்ளது, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string> - <!-- no translation found for bluetooth_active_battery_level_untethered (6662649951391456747) --> - <skip /> + <string name="bluetooth_active_battery_level_untethered" msgid="6662649951391456747">"செயலில் உள்ளது, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> பேட்டரி, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> பேட்டரி"</string> <string name="bluetooth_battery_level" msgid="1447164613319663655">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string> - <!-- no translation found for bluetooth_battery_level_untethered (5974406100211667177) --> - <skip /> + <string name="bluetooth_battery_level_untethered" msgid="5974406100211667177">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> பேட்டரி, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> பேட்டரி"</string> <string name="bluetooth_active_no_battery_level" msgid="8380223546730241956">"செயலில் உள்ளது"</string> <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"மீடியா ஆடியோ"</string> <string name="bluetooth_profile_headset" msgid="7815495680863246034">"ஃபோன் அழைப்புகள்"</string> @@ -268,8 +265,8 @@ <string name="adb_keys_warning_message" msgid="5659849457135841625">"நீங்கள் ஏற்கனவே அனுமதித்த எல்லா கணினிகளிலிருந்தும் USB பிழைத்திருத்தத்திற்கான அணுகலைத் திரும்பப்பெற வேண்டுமா?"</string> <string name="dev_settings_warning_title" msgid="7244607768088540165">"மேம்பட்ட அமைப்புகளை அனுமதிக்கவா?"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"இந்த அமைப்பு மேம்பட்டப் பயன்பாட்டிற்காக மட்டுமே. உங்கள் சாதனம் மற்றும் அதில் உள்ள பயன்பாடுகளைச் சிதைக்கும் அல்லது தவறாகச் செயல்படும் வகையில் பாதிப்பை ஏற்படுத்தும்."</string> - <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB பயன்பாடுகளைச் சரிபார்"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"தீங்கு விளைவிக்கும் செயல்பாட்டை அறிய ADB/ADT மூலம் நிறுவப்பட்டப் பயன்பாடுகளைச் சரிபார்."</string> + <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ஆப்ஸைச் சரிபார்"</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"தீங்கு விளைவிக்கும் செயல்பாட்டை அறிய ADB/ADT மூலம் நிறுவப்பட்ட ஆப்ஸைச் சரிபார்."</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"பெயர்கள் இல்லாத புளூடூத் சாதனங்கள் (MAC முகவரிகள் மட்டும்) காட்டப்படும்"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"மிகவும் அதிகமான ஒலியளவு அல்லது கட்டுப்பாடு இழப்பு போன்ற தொலைநிலைச் சாதனங்களில் ஏற்படும் ஒலி தொடர்பான சிக்கல்கள் இருக்கும் சமயங்களில், புளூடூத் அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கும்."</string> <string name="enable_terminal_title" msgid="95572094356054120">"அக முனையம்"</string> @@ -327,11 +324,11 @@ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"பயனர் வெளியேறியதும் செயல்பாடுகளை நீக்கு"</string> <string name="app_process_limit_title" msgid="4280600650253107163">"பின்புலச் செயல்முறை வரம்பு"</string> <string name="show_all_anrs" msgid="4924885492787069007">"பின்புல ANRகளைக் காட்டு"</string> - <string name="show_all_anrs_summary" msgid="6636514318275139826">"பின்புல ஆப்ஸுக்கு, பயன்பாடு பதிலளிக்கவில்லை என்ற செய்தியைக் காட்டும்"</string> + <string name="show_all_anrs_summary" msgid="6636514318275139826">"பின்புல ஆப்ஸுக்கு, ஆப்ஸ் பதிலளிக்கவில்லை என்ற செய்தியைக் காட்டும்"</string> <string name="show_notification_channel_warnings" msgid="1399948193466922683">"அறிவிப்புச் சேனல் எச்சரிக்கைகளைக் காட்டு"</string> - <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"பயன்பாடானது சரியான சேனல் இல்லாமல் அறிவிப்பை இடுகையிடும் போது, திரையில் எச்சரிக்கையைக் காட்டும்"</string> - <string name="force_allow_on_external" msgid="3215759785081916381">"பயன்பாடுகளை வெளிப்புறச் சேமிப்பிடத்தில் அனுமதி"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், எல்லா பயன்பாட்டையும் வெளிப்புறச் சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string> + <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"ஆப்ஸானது சரியான சேனல் இல்லாமல் அறிவிப்பை இடுகையிடும் போது, திரையில் எச்சரிக்கையைக் காட்டும்"</string> + <string name="force_allow_on_external" msgid="3215759785081916381">"ஆப்ஸை வெளிப்புறச் சேமிப்பிடத்தில் அனுமதி"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், எல்லா ஆப்ஸையும் வெளிப்புறச் சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string> <string name="force_resizable_activities_summary" msgid="6667493494706124459">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமை."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string> @@ -390,8 +387,7 @@ <string name="power_discharge_by" msgid="6453537733650125582">"<xliff:g id="TIME">%1$s</xliff:g> வரை பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"<xliff:g id="TIME">%1$s</xliff:g> வரை பயன்படுத்த முடியும்"</string> <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> வரை"</string> - <!-- no translation found for power_suggestion_extend_battery (4401408879069551485) --> - <skip /> + <string name="power_suggestion_extend_battery" msgid="4401408879069551485">"<xliff:g id="TIME">%1$s</xliff:g> மணிக்குப் பிறகு பேட்டரி நிலையை நீட்டிக்கவும்"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்த முடியும்"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>க்கும் மேல் பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -465,6 +461,5 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ஒவ்வொரு முறையும் கேள்"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"ஆஃப் செய்யும் வரை"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"சற்றுமுன்"</string> - <!-- no translation found for media_transfer_this_device_name (1636276898262571213) --> - <skip /> + <string name="media_transfer_this_device_name" msgid="1636276898262571213">"இந்தச் சாதனம்"</string> </resources> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 62879d200674..cad28aff71ee 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -265,8 +265,8 @@ <string name="adb_keys_warning_message" msgid="5659849457135841625">"ยกเลิกการเข้าถึงเพื่อแก้ปัญหาผ่าน USB จากคอมพิวเตอร์ทุกเครื่องที่คุณได้ให้สิทธิ์ก่อนหน้านี้ไหม"</string> <string name="dev_settings_warning_title" msgid="7244607768088540165">"อนุญาตการตั้งค่าสำหรับการพัฒนาหรือไม่"</string> <string name="dev_settings_warning_message" msgid="2298337781139097964">"การตั้งค่านี้มีไว้เพื่อการพัฒนาเท่านั้น จึงอาจทำให้อุปกรณ์และแอปพลิเคชันที่มีอยู่เสียหายหรือทำงานผิดพลาดได้"</string> - <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ยืนยันแอปพลิเคชันผ่าน USB"</string> - <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ตรวจสอบแอปพลิเคชันที่ติดตั้งผ่าน ADB/ADT เพื่อตรวจดูพฤติกรรมที่เป็นอันตราย"</string> + <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ยืนยันแอปผ่าน USB"</string> + <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ตรวจสอบแอปที่ติดตั้งผ่าน ADB/ADT เพื่อตรวจดูพฤติกรรมที่เป็นอันตราย"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"ระบบจะแสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ (มีเฉพาะที่อยู่ MAC)"</string> <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ปิดใช้ฟีเจอร์การควบคุมระดับเสียงของอุปกรณ์อื่นผ่านบลูทูธในกรณีที่มีปัญหาเกี่ยวกับระดับเสียงของอุปกรณ์ระยะไกล เช่น ระดับเสียงที่ดังเกินไปหรือระดับเสียงที่ไม่มีการควบคุม"</string> <string name="enable_terminal_title" msgid="95572094356054120">"เทอร์มินัลในตัวเครื่อง"</string> @@ -274,7 +274,7 @@ <string name="hdcp_checking_title" msgid="8605478913544273282">"การตรวจสอบ HDCP"</string> <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"ตั้งค่าการตรวจสอบ HDCP"</string> <string name="debug_debugging_category" msgid="6781250159513471316">"การแก้ไขข้อบกพร่อง"</string> - <string name="debug_app" msgid="8349591734751384446">"เลือกแอปพลิเคชันที่จะแก้ไขข้อบกพร่อง"</string> + <string name="debug_app" msgid="8349591734751384446">"เลือกแอปที่จะแก้ไขข้อบกพร่อง"</string> <string name="debug_app_not_set" msgid="718752499586403499">"ไม่มีชุดแอปพลิเคชันแก้ไขข้อบกพร่อง"</string> <string name="debug_app_set" msgid="2063077997870280017">"แอปพลิเคชันแก้ไขข้อบกพร่อง: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="select_application" msgid="5156029161289091703">"เลือกแอปพลิเคชัน"</string> @@ -291,11 +291,11 @@ <string name="pointer_location" msgid="6084434787496938001">"ตำแหน่งของตัวชี้"</string> <string name="pointer_location_summary" msgid="840819275172753713">"การวางซ้อนหน้าจอที่แสดงข้อมูลการแตะ ในปัจจุบัน"</string> <string name="show_touches" msgid="2642976305235070316">"แสดงการแตะ"</string> - <string name="show_touches_summary" msgid="6101183132903926324">"แสดงความคิดเห็นด้วยภาพสำหรับการแตะ"</string> + <string name="show_touches_summary" msgid="6101183132903926324">"แสดงผลตอบสนองแบบภาพเมื่อแตะ"</string> <string name="show_screen_updates" msgid="5470814345876056420">"แสดงการอัปเดตพื้นผิว"</string> - <string name="show_screen_updates_summary" msgid="2569622766672785529">"แฟลชพื้นผิวหน้าต่างทั้งหมดเมื่อมีการอัปเดต"</string> + <string name="show_screen_updates_summary" msgid="2569622766672785529">"กะพริบหน้าต่างทั้งหมดเมื่อมีการอัปเดต"</string> <string name="show_hw_screen_updates" msgid="4117270979975470789">"แสดงมุมมองการอัปเดต"</string> - <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"แสดงมุมมองภายในหน้าต่างขณะลาก"</string> + <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"แสดงมุมมองกะพริบภายในหน้าต่างขณะลาก"</string> <string name="show_hw_layers_updates" msgid="5645728765605699821">"แสดงอัปเดตเลเยอร์ฮาร์ดแวร์"</string> <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"เลเยอร์ฮาร์ดแวร์กะพริบเป็นสีเขียว เมื่อมีการอัปเดต"</string> <string name="debug_hw_overdraw" msgid="2968692419951565417">"แก้ปัญหาการแสดงพิกเซลซ้ำด้วย GPU"</string> @@ -328,13 +328,13 @@ <string name="show_notification_channel_warnings" msgid="1399948193466922683">"แสดงคำเตือนจากช่องทางการแจ้งเตือน"</string> <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"แสดงคำเตือนบนหน้าจอเมื่อแอปโพสต์การแจ้งเตือนโดยไม่มีช่องทางที่ถูกต้อง"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"บังคับให้แอปสามารถใช้ที่เก็บภายนอก"</string> - <string name="force_allow_on_external_summary" msgid="3640752408258034689">"ทำให้สามารถเขียนแอปใดๆ ก็ตามไปยังพื้นที่เก็บข้อมูลภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string> + <string name="force_allow_on_external_summary" msgid="3640752408258034689">"เขียนแอปในพื้นที่เก็บข้อมูลภายนอกได้ โดยไม่คำนึงถึงค่าไฟล์ Manifest"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string> <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string> <string name="enable_freeform_support" msgid="1461893351278940416">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string> <string name="enable_freeform_support_summary" msgid="8247310463288834487">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string> - <string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป ไม่ได้รับการป้องกันในขณะนี้"</string> + <string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อปไม่ได้รับการป้องกันในขณะนี้"</string> <string name="local_backup_password_summary_change" msgid="5376206246809190364">"แตะเพื่อเปลี่ยนแปลงหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string> <string name="local_backup_password_toast_success" msgid="582016086228434290">"ตั้งรหัสผ่านสำหรับการสำรองข้อมูลใหม่แล้ว"</string> <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"รหัสผ่านใหม่และการพิมพ์ยืนยันไม่ตรงกัน"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 7ba5c5e03a15..396dc732d90f 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -428,7 +428,7 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string> <string name="retail_demo_reset_message" msgid="118771671364131297">"Demo modunda sıfırlamak için şifreyi girin"</string> - <string name="retail_demo_reset_next" msgid="8356731459226304963">"Sonraki"</string> + <string name="retail_demo_reset_next" msgid="8356731459226304963">"İleri"</string> <string name="retail_demo_reset_title" msgid="696589204029930100">"Şifre gerekli"</string> <string name="active_input_method_subtypes" msgid="3596398805424733238">"Etkin giriş yöntemleri"</string> <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Sistem dillerini kullan"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index b04765433f9d..a6cfadccf728 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -342,7 +342,7 @@ <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Завантаження…"</string> <string-array name="color_mode_names"> <item msgid="2425514299220523812">"Насичений (за умовчанням)"</item> - <item msgid="8446070607501413455">"Природний"</item> + <item msgid="8446070607501413455">"Природні"</item> <item msgid="6553408765810699025">"Стандартний"</item> </string-array> <string-array name="color_mode_descriptions"> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index b2fc3d99a330..7949d9c0ca13 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -42,8 +42,7 @@ <string name="available_via_passpoint" msgid="1617440946846329613">"دستیاب بذریعہ %1$s"</string> <string name="tap_to_sign_up" msgid="6449724763052579434">"سائن اپ کے لیے تھپتھپائیں"</string> <string name="wifi_connected_no_internet" msgid="8202906332837777829">"منسلک، انٹرنیٹ نہیں ہے"</string> - <!-- no translation found for wifi_limited_connection (7717855024753201527) --> - <skip /> + <string name="wifi_limited_connection" msgid="7717855024753201527">"محدود کنکشن"</string> <string name="wifi_status_no_internet" msgid="5784710974669608361">"انٹرنیٹ نہیں ہے"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"سائن ان درکار ہے"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"رسائی پوائنٹ عارضی طور پر فُل ہے"</string> @@ -75,11 +74,9 @@ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"منسلک ہے (میڈیا کے علاوہ)، بیٹری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"منسلک ہے (فون یا میڈیا کے علاوہ)، بیٹری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_active_battery_level" msgid="3149689299296462009">"فعال، <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string> - <!-- no translation found for bluetooth_active_battery_level_untethered (6662649951391456747) --> - <skip /> + <string name="bluetooth_active_battery_level_untethered" msgid="6662649951391456747">"فعال، بائيں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> بیٹری، دائیں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری"</string> <string name="bluetooth_battery_level" msgid="1447164613319663655">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string> - <!-- no translation found for bluetooth_battery_level_untethered (5974406100211667177) --> - <skip /> + <string name="bluetooth_battery_level_untethered" msgid="5974406100211667177">"بائيں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> بیٹری، دائیں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری"</string> <string name="bluetooth_active_no_battery_level" msgid="8380223546730241956">"فعال"</string> <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"میڈيا آڈیو"</string> <string name="bluetooth_profile_headset" msgid="7815495680863246034">"فون کالز"</string> @@ -390,8 +387,7 @@ <string name="power_discharge_by" msgid="6453537733650125582">"تقریباً <xliff:g id="TIME">%1$s</xliff:g> تک بیٹری چلے گی (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="107616694963545745">"تقریباً <xliff:g id="TIME">%1$s</xliff:g> تک بیٹری چلے گی"</string> <string name="power_discharge_by_only_short" msgid="1372817269546888804">"<xliff:g id="TIME">%1$s</xliff:g> تک"</string> - <!-- no translation found for power_suggestion_extend_battery (4401408879069551485) --> - <skip /> + <string name="power_suggestion_extend_battery" msgid="4401408879069551485">"<xliff:g id="TIME">%1$s</xliff:g> کے بعد بیٹری لائف بڑھائیں"</string> <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> سے کم باقی ہے"</string> <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"<xliff:g id="THRESHOLD">%1$s</xliff:g> سے کم باقی ہے (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> سے زیادہ باقی ہے (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -465,6 +461,5 @@ <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ہر بار پوچھیں"</string> <string name="zen_mode_forever" msgid="2704305038191592967">"یہاں تک کہ آپ آف کر دیں"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"ابھی ابھی"</string> - <!-- no translation found for media_transfer_this_device_name (1636276898262571213) --> - <skip /> + <string name="media_transfer_this_device_name" msgid="1636276898262571213">"یہ آلہ"</string> </resources> diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml index e64ccfa1fa54..164aa93b19f8 100644 --- a/packages/SettingsLib/res/values-uz/arrays.xml +++ b/packages/SettingsLib/res/values-uz/arrays.xml @@ -59,7 +59,7 @@ <item msgid="45075631231212732">"Har doim HDCP tekshiruvidan foydalanilsin"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> - <item msgid="3966341281672645384">"Oʻchiq"</item> + <item msgid="3966341281672645384">"Yoqilmagan"</item> <item msgid="1969681323976948639">"Filtrlar yoniq"</item> <item msgid="8719029132154020716">"Yoniq"</item> </string-array> @@ -150,7 +150,7 @@ <item msgid="4046665544396189228">", faol (telefon)"</item> </string-array> <string-array name="select_logd_size_titles"> - <item msgid="8665206199209698501">"O‘chiq"</item> + <item msgid="8665206199209698501">"Yoqilmagan"</item> <item msgid="1593289376502312923">"64 KB"</item> <item msgid="487545340236145324">"256 KB"</item> <item msgid="2423528675294333831">"1 MB"</item> @@ -158,13 +158,13 @@ <item msgid="2803199102589126938">"16 MB"</item> </string-array> <string-array name="select_logd_size_lowram_titles"> - <item msgid="6089470720451068364">"O‘chiq"</item> + <item msgid="6089470720451068364">"Yoqilmagan"</item> <item msgid="4622460333038586791">"64 KB"</item> <item msgid="2212125625169582330">"256 KB"</item> <item msgid="1704946766699242653">"1 MB"</item> </string-array> <string-array name="select_logd_size_summaries"> - <item msgid="6921048829791179331">"O‘chiq"</item> + <item msgid="6921048829791179331">"Yoqilmagan"</item> <item msgid="2969458029344750262">"Bufer: maks. 64 KB"</item> <item msgid="1342285115665698168">"Bufer: maks. 256 KB"</item> <item msgid="1314234299552254621">"Bufer: maks. 1 MB"</item> @@ -172,13 +172,13 @@ <item msgid="5431354956856655120">"Bufer: maks. 16 MB"</item> </string-array> <string-array name="select_logpersist_titles"> - <item msgid="1744840221860799971">"O‘chiq"</item> + <item msgid="1744840221860799971">"Yoqilmagan"</item> <item msgid="3054662377365844197">"Hammasi"</item> <item msgid="688870735111627832">"Radiodan boshqa hammasi"</item> <item msgid="2850427388488887328">"faqat yadro"</item> </string-array> <string-array name="select_logpersist_summaries"> - <item msgid="2216470072500521830">"O‘chiq"</item> + <item msgid="2216470072500521830">"Yoqilmagan"</item> <item msgid="172978079776521897">"Barcha jurnallar buferi"</item> <item msgid="3873873912383879240">"Radio jurnallar buferidan tashqari hammasi"</item> <item msgid="8489661142527693381">"faqat yadro jurnali buferi"</item> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index ccd6a09adce4..c6b56ad5a3b9 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -23,7 +23,7 @@ <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tarmoqlarni tekshirib chiqishni iloji bo‘lmadi"</string> <string name="wifi_security_none" msgid="7985461072596594400">"Hech qanday"</string> <string name="wifi_remembered" msgid="4955746899347821096">"Saqlandi"</string> - <string name="wifi_disabled_generic" msgid="4259794910584943386">"O‘chiq"</string> + <string name="wifi_disabled_generic" msgid="4259794910584943386">"Yoqilmagan"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP manzilini sozlab bo‘lmadi"</string> <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"Sifatsiz tarmoq sababli ulanib bo‘lmadi"</string> <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string> @@ -238,7 +238,7 @@ <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Translatsiya: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Shaxsiy DNS"</string> <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Shaxsiy DNS rejimini tanlang"</string> - <string name="private_dns_mode_off" msgid="8236575187318721684">"O‘chiq"</string> + <string name="private_dns_mode_off" msgid="8236575187318721684">"Yoqilmagan"</string> <string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"Avtomatik"</string> <string name="private_dns_mode_provider" msgid="8354935160639360804">"Shaxsiy DNS provayderining host nomi"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS provayderining host nomini kiriting"</string> @@ -367,7 +367,7 @@ <string name="button_convert_fbe" msgid="5152671181309826405">"O‘chirib tashlash va o‘girish…"</string> <string name="picture_color_mode" msgid="4560755008730283695">"Rang rejimi"</string> <string name="picture_color_mode_desc" msgid="1141891467675548590">"sRGB ranglaridan foydalanish"</string> - <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"O‘chiq"</string> + <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Yoqilmagan"</string> <string name="daltonizer_mode_monochromacy" msgid="8485709880666106721">"Monoxrom"</string> <string name="daltonizer_mode_deuteranomaly" msgid="5475532989673586329">"Deyteranomaliya (qizil/yashil)"</string> <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"Protanomaliya (qizil/yashil)"</string> @@ -408,7 +408,7 @@ <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Ulangan, lekin quvvat olmayapti"</string> <string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string> <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administrator tomonidan boshqariladi"</string> - <string name="disabled" msgid="9206776641295849915">"O‘chiq"</string> + <string name="disabled" msgid="9206776641295849915">"Yoqilmagan"</string> <string name="external_source_trusted" msgid="2707996266575928037">"Ruxsat berilgan"</string> <string name="external_source_untrusted" msgid="2677442511837596726">"Ruxsat berilmagan"</string> <string name="install_other_apps" msgid="6986686991775883017">"Notanish ilovalarni o‘rnatish"</string> @@ -459,7 +459,7 @@ <string name="alarm_template_far" msgid="3779172822607461675">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="zen_mode_duration_settings_title" msgid="229547412251222757">"Davomiyligi"</string> <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Har safar so‘ralsin"</string> - <string name="zen_mode_forever" msgid="2704305038191592967">"Bekor qilinmaguncha"</string> + <string name="zen_mode_forever" msgid="2704305038191592967">"Rejimdan chiqilgunicha"</string> <string name="time_unit_just_now" msgid="6363336622778342422">"Hozir"</string> <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Shu qurilma"</string> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt index 239b1d464ea3..257943e16149 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt +++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt @@ -83,6 +83,8 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) // Dual tone implies that battery level is a clipped overlay over top of the whole shape private var dualTone = false + private var batteryLevel = 0 + private val invalidateRunnable: () -> Unit = { invalidateSelf() } @@ -173,12 +175,13 @@ 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) - val fillFraction = level / 100f + val fillFraction = batteryLevel / 100f val fillTop = - if (level >= 95) + if (batteryLevel >= 95) fillRect.top else fillRect.top + (fillRect.height() * (1 - fillFraction)) @@ -222,7 +225,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) fillPaint.color = levelColor // Show colorError below this level - if (level <= Companion.CRITICAL_LEVEL && !charging) { + if (batteryLevel <= Companion.CRITICAL_LEVEL && !charging) { c.save() c.clipPath(scaledFill) c.drawPath(levelPath, fillPaint) @@ -243,6 +246,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 { @@ -308,13 +312,13 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) */ public open fun setBatteryLevel(l: Int) { invertFillIcon = if (l >= 67) true else if (l <= 33) false else invertFillIcon - level = l - levelColor = batteryColorForLevel(level) + batteryLevel = l + levelColor = batteryColorForLevel(batteryLevel) invalidateSelf() } public fun getBatteryLevel(): Int { - return level + return batteryLevel } override fun onBoundsChange(bounds: Rect?) { @@ -341,7 +345,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) dualToneBackgroundFill.color = bgColor // Also update the level color, since fillColor may have changed - levelColor = batteryColorForLevel(level) + levelColor = batteryColorForLevel(batteryLevel) invalidateSelf() } diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java deleted file mode 100644 index 4c45a75d876a..000000000000 --- a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.settingslib.users; - -import android.app.ActivityManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.UserInfo; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; - -import com.android.internal.util.UserIcons; - -import java.util.Iterator; -import java.util.List; - -/** - * Helper class for managing users, providing methods for removing, adding and switching users. - * - * @deprecated - Do not use - */ -@Deprecated -public final class UserManagerHelper { - private static final String TAG = "UserManagerHelper"; - private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless"; - private final Context mContext; - private final UserManager mUserManager; - private final ActivityManager mActivityManager; - private OnUsersUpdateListener mUpdateListener; - private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - mUpdateListener.onUsersUpdate(); - } - }; - - public UserManagerHelper(Context context) { - mContext = context; - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - } - - /** - * Registers a listener for updates to all users - removing, adding users or changing user info. - * - * @param listener Instance of {@link OnUsersUpdateListener}. - */ - public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) { - mUpdateListener = listener; - registerReceiver(); - } - - /** - * Unregisters listener by unregistering {@code BroadcastReceiver}. - */ - public void unregisterOnUsersUpdateListener() { - unregisterReceiver(); - } - - /** - * Returns {@code true} if the system is in the headless user 0 model. - * - * @return {@boolean true} if headless system user. - */ - public boolean isHeadlessSystemUser() { - return SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false); - } - - /** - * Gets UserInfo for the foreground user. - * - * Concept of foreground user is relevant for the multi-user deployment. Foreground user - * corresponds to the currently "logged in" user. - * - * @return {@link UserInfo} for the foreground user. - */ - public UserInfo getForegroundUserInfo() { - return mUserManager.getUserInfo(getForegroundUserId()); - } - - /** - * @return Id of the foreground user. - */ - public int getForegroundUserId() { - return mActivityManager.getCurrentUser(); - } - - /** - * Gets UserInfo for the user running the caller process. - * - * Differentiation between foreground user and current process user is relevant for multi-user - * deployments. - * - * Some multi-user aware components (like SystemUI) might run as a singleton - one component - * for all users. Current process user is then always the same for that component, even when - * the foreground user changes. - * - * @return {@link UserInfo} for the user running the current process. - */ - public UserInfo getCurrentProcessUserInfo() { - return mUserManager.getUserInfo(getCurrentProcessUserId()); - } - - /** - * @return Id for the user running the current process. - */ - public int getCurrentProcessUserId() { - return UserHandle.myUserId(); - } - - /** - * Gets all the other users on the system that are not the user running the current process. - * - * @return List of {@code UserInfo} for each user that is not the user running the process. - */ - public List<UserInfo> getAllUsersExcludesCurrentProcessUser() { - return getAllUsersExceptUser(getCurrentProcessUserId()); - } - - /** - * Gets all the existing users on the system that are not the currently running as the - * foreground user. - * - * @return List of {@code UserInfo} for each user that is not the foreground user. - */ - public List<UserInfo> getAllUsersExcludesForegroundUser() { - return getAllUsersExceptUser(getForegroundUserId()); - } - - /** - * Gets all the other users on the system that are not the system user. - * - * @return List of {@code UserInfo} for each user that is not the system user. - */ - public List<UserInfo> getAllUsersExcludesSystemUser() { - return getAllUsersExceptUser(UserHandle.USER_SYSTEM); - } - - /** - * Get all the users except the one with userId passed in. - * - * @param userId of the user not to be returned. - * @return All users other than user with userId. - */ - public List<UserInfo> getAllUsersExceptUser(int userId) { - List<UserInfo> others = mUserManager.getUsers(/* excludeDying= */true); - - for (Iterator<UserInfo> iterator = others.iterator(); iterator.hasNext(); ) { - UserInfo userInfo = iterator.next(); - if (userInfo.id == userId) { - // Remove user with userId from the list. - iterator.remove(); - } - } - return others; - } - - /** - * Gets all the users on the system that are not currently being removed. - */ - public List<UserInfo> getAllUsers() { - if (isHeadlessSystemUser()) { - return getAllUsersExcludesSystemUser(); - } - return mUserManager.getUsers(/* excludeDying= */true); - } - - // User information accessors - - /** - * Checks whether the user is system user (admin). - * - * @param userInfo User to check against system user. - * @return {@code true} if system user, {@code false} otherwise. - */ - public boolean userIsSystemUser(UserInfo userInfo) { - return userInfo.id == UserHandle.USER_SYSTEM; - } - - /** - * Returns whether this user can be removed from the system. - * - * @param userInfo User to be removed - * @return {@code true} if they can be removed, {@code false} otherwise. - */ - public boolean userCanBeRemoved(UserInfo userInfo) { - return !userIsSystemUser(userInfo); - } - - /** - * Checks whether passed in user is the foreground user. - * - * @param userInfo User to check. - * @return {@code true} if foreground user, {@code false} otherwise. - */ - public boolean userIsForegroundUser(UserInfo userInfo) { - return getForegroundUserId() == userInfo.id; - } - - /** - * Checks whether passed in user is the user that's running the current process. - * - * @param userInfo User to check. - * @return {@code true} if user running the process, {@code false} otherwise. - */ - public boolean userIsRunningCurrentProcess(UserInfo userInfo) { - return getCurrentProcessUserId() == userInfo.id; - } - - // Foreground user information accessors. - - /** - * Checks if the foreground user is a guest user. - */ - public boolean foregroundUserIsGuestUser() { - return getForegroundUserInfo().isGuest(); - } - - /** - * Return whether the foreground user has a restriction. - * - * @param restriction Restriction to check. Should be a UserManager.* restriction. - * @return Whether that restriction exists for the foreground user. - */ - public boolean foregroundUserHasUserRestriction(String restriction) { - return mUserManager.hasUserRestriction(restriction, getForegroundUserInfo().getUserHandle()); - } - - /** - * Checks if the foreground user can add new users. - */ - public boolean foregroundUserCanAddUsers() { - return !foregroundUserHasUserRestriction(UserManager.DISALLOW_ADD_USER); - } - - // Current process user information accessors - - /** - * Checks if the calling app is running in a demo user. - */ - public boolean currentProcessRunningAsDemoUser() { - return mUserManager.isDemoUser(); - } - - /** - * Checks if the calling app is running as a guest user. - */ - public boolean currentProcessRunningAsGuestUser() { - return mUserManager.isGuestUser(); - } - - /** - * Checks whether this process is running under the system user. - */ - public boolean currentProcessRunningAsSystemUser() { - return mUserManager.isSystemUser(); - } - - // Current process user restriction accessors - - /** - * Return whether the user running the current process has a restriction. - * - * @param restriction Restriction to check. Should be a UserManager.* restriction. - * @return Whether that restriction exists for the user running the process. - */ - public boolean currentProcessHasUserRestriction(String restriction) { - return mUserManager.hasUserRestriction(restriction); - } - - /** - * Checks if the user running the current process can add new users. - */ - public boolean currentProcessCanAddUsers() { - return !currentProcessHasUserRestriction(UserManager.DISALLOW_ADD_USER); - } - - /** - * Checks if the user running the current process can remove users. - */ - public boolean currentProcessCanRemoveUsers() { - return !currentProcessHasUserRestriction(UserManager.DISALLOW_REMOVE_USER); - } - - /** - * Checks if the user running the current process is allowed to switch to another user. - */ - public boolean currentProcessCanSwitchUsers() { - return !currentProcessHasUserRestriction(UserManager.DISALLOW_USER_SWITCH); - } - - /** - * Checks if the current process user can modify accounts. Demo and Guest users cannot modify - * accounts even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied. - */ - public boolean currentProcessCanModifyAccounts() { - return !currentProcessHasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS) - && !currentProcessRunningAsDemoUser() - && !currentProcessRunningAsGuestUser(); - } - - // User actions - - /** - * Creates a new user on the system. - * - * @param userName Name to give to the newly created user. - * @return Newly created user. - */ - public UserInfo createNewUser(String userName) { - UserInfo user = mUserManager.createUser(userName, 0 /* flags */); - if (user == null) { - // Couldn't create user, most likely because there are too many, but we haven't - // been able to reload the list yet. - Log.w(TAG, "can't create user."); - return null; - } - assignDefaultIcon(user); - return user; - } - - /** - * Tries to remove the user that's passed in. System user cannot be removed. - * If the user to be removed is user currently running the process, - * it switches to the system user first, and then removes the user. - * - * @param userInfo User to be removed - * @return {@code true} if user is successfully removed, {@code false} otherwise. - */ - public boolean removeUser(UserInfo userInfo) { - if (userIsSystemUser(userInfo)) { - Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed."); - return false; - } - - if (userInfo.id == getCurrentProcessUserId()) { - switchToUserId(UserHandle.USER_SYSTEM); - } - - return mUserManager.removeUser(userInfo.id); - } - - /** - * Switches (logs in) to another user. - * - * @param userInfo User to switch to. - */ - public void switchToUser(UserInfo userInfo) { - if (userInfo.id == getForegroundUserId()) { - return; - } - - switchToUserId(userInfo.id); - } - - /** - * Creates a new guest session and switches into the guest session. - * - * @param guestName Username for the guest user. - */ - public void startNewGuestSession(String guestName) { - UserInfo guest = mUserManager.createGuest(mContext, guestName); - if (guest == null) { - // Couldn't create user, most likely because there are too many, but we haven't - // been able to reload the list yet. - Log.w(TAG, "can't create user."); - return; - } - assignDefaultIcon(guest); - switchToUserId(guest.id); - } - - /** - * Gets an icon for the user. - * - * @param userInfo User for which we want to get the icon. - * @return a Bitmap for the icon - */ - public Bitmap getUserIcon(UserInfo userInfo) { - Bitmap picture = mUserManager.getUserIcon(userInfo.id); - - if (picture == null) { - return assignDefaultIcon(userInfo); - } - - return picture; - } - - /** - * Method for scaling a Bitmap icon to a desirable size. - * - * @param icon Bitmap to scale. - * @param desiredSize Wanted size for the icon. - * @return Drawable for the icon, scaled to the new size. - */ - public Drawable scaleUserIcon(Bitmap icon, int desiredSize) { - Bitmap scaledIcon = Bitmap.createScaledBitmap( - icon, desiredSize, desiredSize, true /* filter */); - return new BitmapDrawable(mContext.getResources(), scaledIcon); - } - - /** - * Sets new Username for the user. - * - * @param user User whose name should be changed. - * @param name New username. - */ - public void setUserName(UserInfo user, String name) { - mUserManager.setUserName(user.id, name); - } - - /** - * Gets a bitmap representing the user's default avatar. - * - * @param userInfo User whose avatar should be returned. - * @return Default user icon - */ - public Bitmap getUserDefaultIcon(UserInfo userInfo) { - return UserIcons.convertToBitmap( - UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false)); - } - - /** - * Gets a bitmap representing the default icon for a Guest user. - * - * @return Degault guest icon - */ - public Bitmap getGuestDefaultIcon() { - return UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon( - mContext.getResources(), UserHandle.USER_NULL, false)); - } - - private void registerReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_USER_REMOVED); - filter.addAction(Intent.ACTION_USER_ADDED); - filter.addAction(Intent.ACTION_USER_INFO_CHANGED); - filter.addAction(Intent.ACTION_USER_SWITCHED); - filter.addAction(Intent.ACTION_USER_STOPPED); - filter.addAction(Intent.ACTION_USER_UNLOCKED); - mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null); - } - - /** - * Assigns a default icon to a user according to the user's id. - * - * @param userInfo User to assign a default icon to. - * @return Bitmap that has been assigned to the user. - */ - private Bitmap assignDefaultIcon(UserInfo userInfo) { - Bitmap bitmap = userInfo.isGuest() ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo); - mUserManager.setUserIcon(userInfo.id, bitmap); - return bitmap; - } - - private void switchToUserId(int id) { - try { - mActivityManager.switchUser(id); - } catch (Exception e) { - Log.e(TAG, "Couldn't switch user.", e); - } - } - - private void unregisterReceiver() { - mContext.unregisterReceiver(mUserChangeReceiver); - } - - /** - * Interface for listeners that want to register for receiving updates to changes to the users - * on the system including removing and adding users, and changing user info. - */ - public interface OnUsersUpdateListener { - /** - * Method that will get called when users list has been changed. - */ - void onUsersUpdate(); - } -} diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java deleted file mode 100644 index 46557d3106af..000000000000 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.settingslib.users; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.UserInfo; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.UserHandle; -import android.os.UserManager; - -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(AndroidJUnit4.class) -public class UserManagerHelperTest { - @Mock - private Context mContext; - @Mock - private UserManager mUserManager; - @Mock - private ActivityManager mActivityManager; - @Mock - private UserManagerHelper.OnUsersUpdateListener mTestListener; - - private UserManagerHelper mHelper; - private UserInfo mCurrentProcessUser; - private UserInfo mSystemUser; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); - when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager); - when(mContext.getResources()) - .thenReturn(InstrumentationRegistry.getTargetContext().getResources()); - mHelper = new UserManagerHelper(mContext); - - mCurrentProcessUser = createUserInfoForId(UserHandle.myUserId()); - mSystemUser = createUserInfoForId(UserHandle.USER_SYSTEM); - when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(mCurrentProcessUser); - } - - @Test - public void userIsSystemUser() { - UserInfo testInfo = new UserInfo(); - - testInfo.id = UserHandle.USER_SYSTEM; - assertThat(mHelper.userIsSystemUser(testInfo)).isTrue(); - - testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id. - assertThat(mHelper.userIsSystemUser(testInfo)).isFalse(); - } - - @Test - public void getAllUsersExcludesSystemUser() { - UserInfo otherUser1 = createUserInfoForId(10); - UserInfo otherUser2 = createUserInfoForId(11); - UserInfo otherUser3 = createUserInfoForId(12); - - List<UserInfo> testUsers = new ArrayList<>(); - testUsers.add(otherUser1); - testUsers.add(otherUser2); - testUsers.add(mSystemUser); - testUsers.add(otherUser3); - - when(mUserManager.getUsers(true)).thenReturn(testUsers); - - // Should return 3 users that don't have SYSTEM USER id. - assertThat(mHelper.getAllUsersExcludesSystemUser()).hasSize(3); - assertThat(mHelper.getAllUsersExcludesSystemUser()) - .containsExactly(otherUser1, otherUser2, otherUser3); - } - - @Test - public void getAllUsersExceptUser() { - UserInfo user1 = createUserInfoForId(10); - UserInfo user2 = createUserInfoForId(10); - UserInfo user3 = createUserInfoForId(12); - - List<UserInfo> testUsers = new ArrayList<>(); - testUsers.add(user1); - testUsers.add(user2); - testUsers.add(user3); - - when(mUserManager.getUsers(true)).thenReturn(new ArrayList<>(testUsers)); - - // Should return all 3 users. - assertThat(mHelper.getAllUsersExceptUser(9).size()).isEqualTo(3); - - // Should return only user 12. - assertThat(mHelper.getAllUsersExceptUser(10).size()).isEqualTo(1); - assertThat(mHelper.getAllUsersExceptUser(10)).contains(user3); - - when(mUserManager.getUsers(true)).thenReturn(new ArrayList<>(testUsers)); - - // Should drop user 12. - assertThat(mHelper.getAllUsersExceptUser(12).size()).isEqualTo(2); - assertThat(mHelper.getAllUsersExceptUser(12)).contains(user1); - assertThat(mHelper.getAllUsersExceptUser(12)).contains(user2); - } - - @Test - public void getAllUsers() { - int currentUser = UserHandle.myUserId(); - - UserInfo otherUser1 = createUserInfoForId(currentUser + 1); - UserInfo otherUser2 = createUserInfoForId(currentUser - 1); - UserInfo otherUser3 = createUserInfoForId(currentUser + 2); - - List<UserInfo> testUsers = new ArrayList<>(); - testUsers.add(otherUser1); - testUsers.add(otherUser2); - testUsers.add(mCurrentProcessUser); - testUsers.add(otherUser3); - - when(mUserManager.getUsers(true)).thenReturn(testUsers); - - assertThat(mHelper.getAllUsers().size()).isEqualTo(4); - assertThat(mHelper.getAllUsers()) - .containsExactly(mCurrentProcessUser, otherUser1, otherUser2, otherUser3); - } - - @Test - public void userCanBeRemoved() { - UserInfo testInfo = new UserInfo(); - - // System user cannot be removed. - testInfo.id = UserHandle.USER_SYSTEM; - assertThat(mHelper.userCanBeRemoved(testInfo)).isFalse(); - - testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id. - assertThat(mHelper.userCanBeRemoved(testInfo)).isTrue(); - } - - @Test - public void currentProcessCanAddUsers() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(false); - assertThat(mHelper.currentProcessCanAddUsers()).isTrue(); - - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(true); - assertThat(mHelper.currentProcessCanAddUsers()).isFalse(); - } - - @Test - public void currentProcessCanRemoveUsers() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(false); - assertThat(mHelper.currentProcessCanRemoveUsers()).isTrue(); - - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(true); - assertThat(mHelper.currentProcessCanRemoveUsers()).isFalse(); - } - - @Test - public void currentProcessCanSwitchUsers() { - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false); - assertThat(mHelper.currentProcessCanSwitchUsers()).isTrue(); - - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true); - assertThat(mHelper.currentProcessCanSwitchUsers()).isFalse(); - } - - @Test - public void currentProcessRunningAsGuestCannotModifyAccounts() { - assertThat(mHelper.currentProcessCanModifyAccounts()).isTrue(); - - when(mUserManager.isGuestUser()).thenReturn(true); - assertThat(mHelper.currentProcessCanModifyAccounts()).isFalse(); - } - - @Test - public void currentProcessRunningAsDemoUserCannotModifyAccounts() { - assertThat(mHelper.currentProcessCanModifyAccounts()).isTrue(); - - when(mUserManager.isDemoUser()).thenReturn(true); - assertThat(mHelper.currentProcessCanModifyAccounts()).isFalse(); - } - - @Test - public void currentProcessWithDisallowModifyAccountsRestrictionCannotModifyAccounts() { - assertThat(mHelper.currentProcessCanModifyAccounts()).isTrue(); - - when(mUserManager.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) - .thenReturn(true); - assertThat(mHelper.currentProcessCanModifyAccounts()).isFalse(); - } - - @Test - public void createNewUser() { - // Verify createUser on UserManager gets called. - mHelper.createNewUser("Test User"); - verify(mUserManager).createUser("Test User", 0); - - when(mUserManager.createUser("Test User", 0)).thenReturn(null); - assertThat(mHelper.createNewUser("Test User")).isNull(); - - UserInfo newUser = new UserInfo(); - newUser.name = "Test User"; - when(mUserManager.createUser("Test User", 0)).thenReturn(newUser); - assertThat(mHelper.createNewUser("Test User")).isEqualTo(newUser); - } - - @Test - public void removeUser() { - // Cannot remove system user. - assertThat(mHelper.removeUser(mSystemUser)).isFalse(); - - // Removing non-current, non-system user, simply calls removeUser. - UserInfo userToRemove = createUserInfoForId(mCurrentProcessUser.id + 2); - - mHelper.removeUser(userToRemove); - verify(mUserManager).removeUser(mCurrentProcessUser.id + 2); - } - - @Test - public void startNewGuestSession() { - mHelper.startNewGuestSession("Test Guest"); - verify(mUserManager).createGuest(mContext, "Test Guest"); - - UserInfo guestInfo = new UserInfo(21, "Test Guest", UserInfo.FLAG_GUEST); - when(mUserManager.createGuest(mContext, "Test Guest")).thenReturn(guestInfo); - mHelper.startNewGuestSession("Test Guest"); - verify(mActivityManager).switchUser(21); - } - - @Test - public void getUserIcon() { - mHelper.getUserIcon(mCurrentProcessUser); - verify(mUserManager).getUserIcon(mCurrentProcessUser.id); - } - - @Test - public void scaleUserIcon() { - Bitmap fakeIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); - Drawable scaledIcon = mHelper.scaleUserIcon(fakeIcon, 300); - assertThat(scaledIcon.getIntrinsicWidth()).isEqualTo(300); - assertThat(scaledIcon.getIntrinsicHeight()).isEqualTo(300); - } - - @Test - public void setUserName() { - UserInfo testInfo = createUserInfoForId(mCurrentProcessUser.id + 3); - mHelper.setUserName(testInfo, "New Test Name"); - verify(mUserManager).setUserName(mCurrentProcessUser.id + 3, "New Test Name"); - } - - @Test - public void registerUserChangeReceiver() { - mHelper.registerOnUsersUpdateListener(mTestListener); - - ArgumentCaptor<BroadcastReceiver> receiverCaptor = - ArgumentCaptor.forClass(BroadcastReceiver.class); - ArgumentCaptor<UserHandle> handleCaptor = ArgumentCaptor.forClass(UserHandle.class); - ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class); - ArgumentCaptor<String> permissionCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class); - - verify(mContext).registerReceiverAsUser( - receiverCaptor.capture(), - handleCaptor.capture(), - filterCaptor.capture(), - permissionCaptor.capture(), - handlerCaptor.capture()); - - // Verify we're listening to Intents from ALL users. - assertThat(handleCaptor.getValue()).isEqualTo(UserHandle.ALL); - - // Verify the presence of each intent in the filter. - // Verify the exact number of filters. Every time a new intent is added, this test should - // get updated. - assertThat(filterCaptor.getValue().countActions()).isEqualTo(6); - assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_REMOVED)).isTrue(); - assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_ADDED)).isTrue(); - assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue(); - assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_SWITCHED)).isTrue(); - assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_STOPPED)).isTrue(); - assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_UNLOCKED)).isTrue(); - - - // Verify that calling the receiver calls the listener. - receiverCaptor.getValue().onReceive(mContext, new Intent()); - verify(mTestListener).onUsersUpdate(); - - assertThat(permissionCaptor.getValue()).isNull(); - assertThat(handlerCaptor.getValue()).isNull(); - - - // Unregister the receiver. - mHelper.unregisterOnUsersUpdateListener(); - verify(mContext).unregisterReceiver(receiverCaptor.getValue()); - } - - private UserInfo createUserInfoForId(int id) { - UserInfo userInfo = new UserInfo(); - userInfo.id = id; - return userInfo; - } -} 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/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java deleted file mode 100644 index 83cc39a8a1a9..000000000000 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settingslib.users; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.pm.UserInfo; -import android.os.UserHandle; -import android.os.UserManager; - -import com.android.settingslib.testutils.shadow.ShadowActivityManager; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.Resetter; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = { ShadowActivityManager.class, UserManagerHelperRoboTest.ShadowUserHandle.class}) -public class UserManagerHelperRoboTest { - @Mock - private Context mContext; - @Mock - private UserManager mUserManager; - - private UserManagerHelper mHelper; - - @Before - public void setUpMocksAndUserManagerHelper() { - MockitoAnnotations.initMocks(this); - when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); - when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn( - RuntimeEnvironment.application.getSystemService(ActivityManager.class)); - mHelper = new UserManagerHelper(mContext); - } - - @After - public void tearDown() { - ShadowActivityManager.getShadow().reset(); - } - - @Test - public void getForegroundUserId() { - ShadowActivityManager.setCurrentUser(15); - assertThat(mHelper.getForegroundUserId()).isEqualTo(15); - } - - @Test - public void getForegroundUserInfo() { - ShadowActivityManager.setCurrentUser(17); - when(mUserManager.getUserInfo(ActivityManager.getCurrentUser())) - .thenReturn(createUserInfoForId(ActivityManager.getCurrentUser())); - assertThat(mHelper.getForegroundUserInfo().id).isEqualTo(17); - } - - @Test - public void getCurrentProcessUserId() { - ShadowUserHandle.setUid(11); - assertThat(mHelper.getCurrentProcessUserId()).isEqualTo(11); - } - - @Test - public void getCurrentProcessUserInfo() { - ShadowUserHandle.setUid(12); - when(mUserManager.getUserInfo(UserHandle.myUserId())) - .thenReturn(createUserInfoForId(UserHandle.myUserId())); - assertThat(mHelper.getCurrentProcessUserInfo().id).isEqualTo(12); - } - - @Test - public void getAllUsersExcludesCurrentProcessUser() { - ShadowUserHandle.setUid(12); - UserInfo currentProcessUser = createUserInfoForId(12); - - UserInfo otherUser1 = createUserInfoForId(13); - UserInfo otherUser2 = createUserInfoForId(11); - UserInfo otherUser3 = createUserInfoForId(14); - - List<UserInfo> testUsers = new ArrayList<>(); - testUsers.add(otherUser1); - testUsers.add(otherUser2); - testUsers.add(currentProcessUser); - testUsers.add(otherUser3); - - when(mUserManager.getUsers(true)).thenReturn(testUsers); - - // Should return 3 users that don't have currentProcessUser id. - assertThat(mHelper.getAllUsersExcludesCurrentProcessUser()).hasSize(3); - assertThat(mHelper.getAllUsersExcludesCurrentProcessUser()) - .containsExactly(otherUser1, otherUser2, otherUser3); - } - - @Test - public void getAllUsersExcludesForegroundUser() { - ShadowActivityManager.setCurrentUser(17); - UserInfo foregroundUser = createUserInfoForId(17); - - UserInfo otherUser1 = createUserInfoForId(11); - UserInfo otherUser2 = createUserInfoForId(18); - UserInfo otherUser3 = createUserInfoForId(16); - - List<UserInfo> testUsers = new ArrayList<>(); - testUsers.add(otherUser1); - testUsers.add(otherUser2); - testUsers.add(foregroundUser); - testUsers.add(otherUser3); - - when(mUserManager.getUsers(true)).thenReturn(testUsers); - - // Should return 3 users that don't have foregroundUser id. - assertThat(mHelper.getAllUsersExcludesForegroundUser()).hasSize(3); - assertThat(mHelper.getAllUsersExcludesForegroundUser()) - .containsExactly(otherUser1, otherUser2, otherUser3); - } - - @Test - public void userIsForegroundUser() { - ShadowActivityManager.setCurrentUser(10); - assertThat(mHelper.userIsForegroundUser(createUserInfoForId(10))).isTrue(); - assertThat(mHelper.userIsForegroundUser(createUserInfoForId(11))).isFalse(); - - ShadowActivityManager.setCurrentUser(11); - assertThat(mHelper.userIsForegroundUser(createUserInfoForId(11))).isTrue(); - } - - @Test - public void userIsRunningCurrentProcess() { - ShadowUserHandle.setUid(10); - assertThat(mHelper.userIsRunningCurrentProcess(createUserInfoForId(10))).isTrue(); - assertThat(mHelper.userIsRunningCurrentProcess(createUserInfoForId(11))).isFalse(); - - ShadowUserHandle.setUid(11); - assertThat(mHelper.userIsRunningCurrentProcess(createUserInfoForId(11))).isTrue(); - } - - @Test - public void removingCurrentProcessUserSwitchesToSystemUser() { - // Set currentProcess user to be user 10. - ShadowUserHandle.setUid(10); - - // Removing a currentProcess user, calls "switch" to system user - mHelper.removeUser(createUserInfoForId(10)); - assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isTrue(); - assertThat(ShadowActivityManager.getShadow().getUserSwitchedTo()).isEqualTo(0); - - verify(mUserManager).removeUser(10); - } - - @Test - public void switchToUser() { - ShadowActivityManager.setCurrentUser(20); - - // Switching to foreground user doesn't do anything. - mHelper.switchToUser(createUserInfoForId(20)); - assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isFalse(); - - // Switching to non-foreground user, simply calls switchUser. - UserInfo userToSwitchTo = new UserInfo(22, "Test User", 0); - mHelper.switchToUser(userToSwitchTo); - assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isTrue(); - assertThat(ShadowActivityManager.getShadow().getUserSwitchedTo()).isEqualTo(22); - } - - private UserInfo createUserInfoForId(int id) { - UserInfo userInfo = new UserInfo(); - userInfo.id = id; - return userInfo; - } - - @Implements(UserHandle.class) - public static class ShadowUserHandle { - private static int sUid = 0; // SYSTEM by default - - public static void setUid(int uid) { - sUid = uid; - } - - @Implementation - public static int myUserId() { - return sUid; - } - - @Resetter - public static void reset() { - sUid = 0; - } - } -} 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/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml index b16e06207ca3..49c16bee7b1f 100644 --- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml +++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml @@ -23,21 +23,20 @@ android:layout_width="wrap_content" android:layout_marginLeft="@dimen/ongoing_appops_chip_margin" android:layout_marginRight="@dimen/ongoing_appops_chip_margin" - android:layout_gravity="center_vertical|start" + android:layout_gravity="center_vertical|end" android:gravity="center_vertical" android:orientation="horizontal" - android:focusable="true"> + android:focusable="true" > <FrameLayout android:id="@+id/background" android:layout_height="@dimen/ongoing_appops_chip_height" - android:layout_width="wrap_content" - > + android:minWidth="48dp" + android:layout_width="wrap_content" > <LinearLayout android:id="@+id/icons_container" android:layout_height="match_parent" android:layout_width="wrap_content" - android:layout_gravity="center" android:gravity="center_vertical" /> </FrameLayout> 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/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 74924fb5562c..bfdb21877277 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1044,7 +1044,7 @@ <!-- Margin between icons of Ongoing App Ops chip when QS--> <dimen name="ongoing_appops_chip_icon_margin_expanded">2dp</dimen> <!-- Icon size of Ongoing App Ops chip --> - <dimen name="ongoing_appops_chip_icon_size">@*android:dimen/status_bar_icon_size</dimen> + <dimen name="ongoing_appops_chip_icon_size">@dimen/status_bar_icon_drawing_size</dimen> <!-- Radius of Ongoing App Ops chip corners --> <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 444cabfcc50e..f121c8ec5de0 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1331,6 +1331,14 @@ <!-- Content description for accessibility: Clear the odi caption tool tip. [CHAR LIMIT=NONE] --> <string name="accessibility_volume_close_odi_captions_tip">Close captions tip</string> + <!-- Content description for accessibility: Captions button. [CHAR LIMIT=NONE] --> + <string name="volume_odi_captions_content_description">Captions overlay</string> + + <!-- Content description for accessibility: Hint if click will enable. [CHAR LIMIT=NONE] --> + <string name="volume_odi_captions_hint_enable">enable</string> + <!-- Content description for accessibility: Hint if click will disable. [CHAR LIMIT=NONE] --> + <string name="volume_odi_captions_hint_disable">disable</string> + <!-- content description for audio output chooser [CHAR LIMIT=NONE]--> <string name="accessibility_output_chooser">Switch output device</string> diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 64517bae6d6b..eca39262dfb5 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -16,14 +16,22 @@ package com.android.keyguard; +import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; + +import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; + import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; +import android.telephony.CarrierConfigManager; +import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; @@ -36,6 +44,7 @@ import com.android.settingslib.WirelessUtils; import com.android.systemui.Dependency; import com.android.systemui.keyguard.WakefulnessLifecycle; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -113,6 +122,17 @@ public class CarrierTextController { } }; + private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveMobileDataSubscription = subId; + if (mKeyguardUpdateMonitor != null) { + updateCarrierText(); + } + } + }; + /** * The status of this lock screen. Primarily used for widgets on LockScreen. */ @@ -200,6 +220,8 @@ public class CarrierTextController { * @param callback Callback to provide text updates */ public void setListening(CarrierTextCallback callback) { + TelephonyManager telephonyManager = ((TelephonyManager) mContext + .getSystemService(Context.TELEPHONY_SERVICE)); if (callback != null) { mCarrierTextCallback = callback; if (ConnectivityManager.from(mContext).isNetworkSupported( @@ -207,6 +229,8 @@ public class CarrierTextController { mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); mKeyguardUpdateMonitor.registerCallback(mCallback); mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + telephonyManager.listen(mPhoneStateListener, + LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); } else { // Don't listen and clear out the text when the device isn't a phone. mKeyguardUpdateMonitor = null; @@ -218,6 +242,35 @@ public class CarrierTextController { mKeyguardUpdateMonitor.removeCallback(mCallback); mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); } + telephonyManager.listen(mPhoneStateListener, LISTEN_NONE); + } + } + + /** + * STOPSHIP(b/130246708) remove when no longer needed for testing purpose. + * @param subscriptions + */ + private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) { + if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) { + SubscriptionInfo info1 = subscriptions.get(0); + SubscriptionInfo info2 = subscriptions.get(1); + if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { + // If both subscriptions are primary, show both. + if (!info1.isOpportunistic() && !info2.isOpportunistic()) return; + + // If carrier required, always show signal bar of primary subscription. + // Otherwise, show whichever subscription is currently active for Internet. + boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig() + .getBoolean(CarrierConfigManager + .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN); + if (alwaysShowPrimary) { + subscriptions.remove(info1.isOpportunistic() ? info1 : info2); + } else { + subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription + ? info2 : info1); + } + + } } } @@ -226,7 +279,17 @@ public class CarrierTextController { boolean anySimReadyAndInService = false; CharSequence displayText = null; - List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); + // STOPSHIP(b/130246708) revert to mKeyguardUpdateMonitor.getSubscriptionInfo(false). + SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE)); + List<SubscriptionInfo> subs = subscriptionManager.getActiveSubscriptionInfoList(false); + + if (subs == null) { + subs = new ArrayList<>(); + } else { + filterMobileSubscriptionInSameGroup(subs); + } + final int numSubs = subs.size(); final int[] subsIds = new int[numSubs]; // This array will contain in position i, the index of subscription in slot ID i. @@ -311,20 +374,23 @@ public class CarrierTextController { displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, allSimsMissing); + boolean airplaneMode = false; // APM (airplane mode) != no carrier state. There are carrier services // (e.g. WFC = Wi-Fi calling) which may operate in APM. if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { displayText = getAirplaneModeMessage(); + airplaneMode = true; } - if (TextUtils.isEmpty(displayText)) { + if (TextUtils.isEmpty(displayText) && !airplaneMode) { displayText = TextUtils.join(mSeparator, carrierNames); } final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( displayText, carrierNames, !allSimsMissing, - subsIds); + subsIds, + airplaneMode); postToCallback(info); } @@ -525,14 +591,22 @@ public class CarrierTextController { public final CharSequence[] listOfCarriers; public final boolean anySimReady; public final int[] subscriptionIds; + public boolean airplaneMode; @VisibleForTesting public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, boolean anySimReady, int[] subscriptionIds) { + this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false); + } + + @VisibleForTesting + public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, + boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) { this.carrierText = carrierText; this.listOfCarriers = listOfCarriers; this.anySimReady = anySimReady; this.subscriptionIds = subscriptionIds; + this.airplaneMode = airplaneMode; } } 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/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 70f2ccee7d60..a4219402259e 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -293,6 +293,7 @@ public class Dependency extends SystemUI { @Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper; @Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper; @Inject Lazy<SensorPrivacyController> mSensorPrivacyController; + @Inject Lazy<DumpController> mDumpController; @Inject public Dependency() { @@ -464,7 +465,7 @@ public class Dependency extends SystemUI { mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get); mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get); mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get); - + mProviders.put(DumpController.class, mDumpController::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add @@ -478,6 +479,11 @@ public class Dependency extends SystemUI { @Override public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { super.dump(fd, pw, args); + + // Make sure that the DumpController gets added to mDependencies, as they are only added + // with Dependency#get. + getDependency(DumpController.class); + pw.println("Dumping existing controllers:"); mDependencies.values().stream().filter(obj -> obj instanceof Dumpable) .forEach(o -> ((Dumpable) o).dump(fd, pw, args)); diff --git a/packages/SystemUI/src/com/android/systemui/DumpController.kt b/packages/SystemUI/src/com/android/systemui/DumpController.kt new file mode 100644 index 000000000000..646abb5c2c5a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/DumpController.kt @@ -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.systemui + +import android.util.Log +import androidx.annotation.GuardedBy +import com.android.internal.util.Preconditions +import java.io.FileDescriptor +import java.io.PrintWriter +import java.lang.ref.WeakReference +import javax.inject.Inject +import javax.inject.Singleton + +// TODO: Move all Dumpable dependencies to use DumpController +/** + * Controller that allows any [Dumpable] to subscribe and be dumped along with other SystemUI + * dependencies. + */ +@Singleton +class DumpController @Inject constructor() : Dumpable { + + companion object { + private const val TAG = "DumpController" + private const val DEBUG = false + } + + @GuardedBy("listeners") + private val listeners = mutableListOf<WeakReference<Dumpable>>() + val numListeners: Int + get() = listeners.size + + /** + * Adds a [Dumpable] listener to be dumped. It will only be added if it is not already tracked. + * + * @param listener the [Dumpable] to be added + */ + fun addListener(listener: Dumpable) { + Preconditions.checkNotNull(listener, "The listener to be added cannot be null") + if (DEBUG) Log.v(TAG, "*** register callback for $listener") + synchronized<Unit>(listeners) { + if (listeners.any { it.get() == listener }) { + if (DEBUG) { + Log.e(TAG, "Object tried to add another callback") + } + } else { + listeners.add(WeakReference(listener)) + } + } + } + + /** + * Removes a listener from the list of elements to be dumped. + * + * @param listener the [Dumpable] to be removed. + */ + fun removeListener(listener: Dumpable) { + if (DEBUG) Log.v(TAG, "*** unregister callback for $listener") + synchronized(listeners) { + listeners.removeAll { it.get() == listener || it.get() == null } + } + } + + /** + * Dump all the [Dumpable] registered with the controller + */ + override fun dump(fd: FileDescriptor?, pw: PrintWriter, args: Array<String>?) { + pw.println("DumpController state:") + synchronized(listeners) { + listeners.forEach { it.get()?.dump(fd, pw, args) } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java index c92767763cb4..39e0dff5675b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java @@ -308,7 +308,7 @@ public abstract class BiometricDialogView extends LinearLayout { protected void updateIcon(int lastState, int newState) { final Drawable icon = getAnimationForTransition(lastState, newState); if (icon == null) { - Log.e(TAG, "Animation not found"); + Log.e(TAG, "Animation not found, " + lastState + " -> " + newState); return; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java index 9fba44b76863..d26968635dc2 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java @@ -330,6 +330,10 @@ public class FaceDialogView extends BiometricDialogView { return true; } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) { return true; + } else if (oldState == STATE_ERROR && newState == STATE_PENDING_CONFIRMATION) { + return true; + } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATED) { + return true; } return false; } @@ -364,6 +368,10 @@ public class FaceDialogView extends BiometricDialogView { iconRes = R.drawable.face_dialog_face_blue_to_checkmark; } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) { iconRes = R.drawable.face_dialog_face_gray_to_checkmark; + } else if (oldState == STATE_ERROR && newState == STATE_PENDING_CONFIRMATION) { + iconRes = R.drawable.face_dialog_face_gray_to_face_blue; + } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATED) { + iconRes = R.drawable.face_dialog_face_blue_to_checkmark; } else { return null; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java index c9b30ba3ce8d..412da1428eca 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java @@ -66,6 +66,9 @@ public class FingerprintDialogView extends BiometricDialogView { } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) { // TODO(b/77328470): add animation when fingerprint is authenticated return false; + } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATED) { + // TODO(b/77328470): add animation when fingerprint is authenticated + return false; } return false; } @@ -93,6 +96,9 @@ public class FingerprintDialogView extends BiometricDialogView { } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) { // TODO(b/77328470): add animation when fingerprint is authenticated iconRes = R.drawable.fingerprint_dialog_fp_to_error; + } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATED) { + // TODO(b/77328470): add animation when fingerprint is authenticated + iconRes = R.drawable.fingerprint_dialog_fp_to_error; } else { return null; } 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 93effed5958e..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(); } @@ -585,23 +578,24 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe private boolean shouldAutoExpand(NotificationEntry entry) { Notification.BubbleMetadata metadata = entry.getBubbleMetadata(); return metadata != null && metadata.getAutoExpandBubble() - && isForegroundApp(entry.notification.getPackageName()); + && isForegroundApp(mContext, entry.notification.getPackageName()); } private void updateShowInShadeForSuppressNotification(NotificationEntry entry) { boolean suppressNotification = entry.getBubbleMetadata() != null && entry.getBubbleMetadata().getSuppressNotification() - && isForegroundApp(entry.notification.getPackageName()); + && isForegroundApp(mContext, entry.notification.getPackageName()); entry.setShowInShadeWhenBubble(!suppressNotification); } /** * Return true if the applications with the package name is running in foreground. * + * @param context application context. * @param pkgName application package name. */ - private boolean isForegroundApp(String pkgName) { - ActivityManager am = mContext.getSystemService(ActivityManager.class); + public static boolean isForegroundApp(Context context, String pkgName) { + ActivityManager am = context.getSystemService(ActivityManager.class); List<RunningTaskInfo> tasks = am.getRunningTasks(1 /* maxNum */); return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); } @@ -620,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/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 285d4aab4f66..17275ad58240 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -723,7 +723,9 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList action, mStackView.getNormalizedXPosition(), mStackView.getNormalizedYPosition(), - entry.showInShadeWhenBubble()); + entry.showInShadeWhenBubble(), + entry.isForegroundService(), + BubbleController.isForegroundApp(mContext, notification.getPackageName())); } private int getDimenForPackageUser(int resId, String pkg, int userId) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 1f1a3e43c0a2..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 */, @@ -1107,7 +999,9 @@ public class BubbleStackView extends FrameLayout { action, getNormalizedXPosition(), getNormalizedYPosition(), - false /* unread notification */); + false /* unread bubble */, + false /* on-going bubble */, + false /* foreground bubble */); } else { StatusBarNotification notification = bubble.entry.notification; StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, @@ -1119,7 +1013,9 @@ public class BubbleStackView extends FrameLayout { action, getNormalizedXPosition(), getNormalizedYPosition(), - bubble.entry.showInShadeWhenBubble()); + bubble.entry.showInShadeWhenBubble(), + bubble.entry.isForegroundService(), + BubbleController.isForegroundApp(mContext, notification.getPackageName())); } } 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/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt index 23742c0953bb..a5a915b88cad 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -16,13 +16,12 @@ package com.android.systemui.privacy import android.content.Context import android.util.AttributeSet +import android.view.Gravity import android.view.ViewGroup import android.widget.FrameLayout import android.widget.ImageView import android.widget.LinearLayout -import com.android.systemui.Dependency import com.android.systemui.R -import com.android.systemui.statusbar.policy.KeyguardMonitor class OngoingPrivacyChip @JvmOverloads constructor( context: Context, @@ -51,8 +50,7 @@ class OngoingPrivacyChip @JvmOverloads constructor( updateView() } } - @Suppress("DEPRECATION") - private val keyguardMonitor = Dependency.get(KeyguardMonitor::class.java) + var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>()) var privacyList = emptyList<PrivacyItem>() set(value) { @@ -94,14 +92,16 @@ class OngoingPrivacyChip @JvmOverloads constructor( if (!privacyList.isEmpty()) { generateContentDescription() setIcons(builder, iconsContainer) + val lp = iconsContainer.layoutParams as FrameLayout.LayoutParams + lp.gravity = Gravity.CENTER_VERTICAL or + (if (expanded) Gravity.CENTER_HORIZONTAL else Gravity.END) + iconsContainer.layoutParams = lp } else { iconsContainer.removeAllViews() } requestLayout() } - private fun amISecure() = keyguardMonitor.isShowing && keyguardMonitor.isSecure - private fun generateContentDescription() { val typesText = builder.joinTypes() contentDescription = context.getString( diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt index 3f581c4de5fb..290942412eed 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt @@ -24,10 +24,14 @@ import com.android.systemui.R typealias Privacy = PrivacyType -enum class PrivacyType(val nameId: Int, val iconId: Int) { - TYPE_CAMERA(R.string.privacy_type_camera, R.drawable.stat_sys_camera), - TYPE_MICROPHONE(R.string.privacy_type_microphone, R.drawable.stat_sys_mic_none), - TYPE_LOCATION(R.string.privacy_type_location, R.drawable.stat_sys_location); +enum class PrivacyType(private val nameId: Int, val iconId: Int) { + // This is uses the icons used by the corresponding permission groups in the AndroidManifest + TYPE_CAMERA(R.string.privacy_type_camera, + com.android.internal.R.drawable.perm_group_camera), + TYPE_MICROPHONE(R.string.privacy_type_microphone, + com.android.internal.R.drawable.perm_group_microphone), + TYPE_LOCATION(R.string.privacy_type_location, + com.android.internal.R.drawable.perm_group_location); fun getName(context: Context) = context.resources.getString(nameId) 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/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java index 0eeaa9b75382..7de8b74f30cc 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java @@ -139,43 +139,49 @@ public class QSCarrierGroup extends LinearLayout implements @Override public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { - if (info.anySimReady) { - boolean[] slotSeen = new boolean[SIM_SLOTS]; - if (info.listOfCarriers.length == info.subscriptionIds.length) { - for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) { - int slot = getSlotIndex(info.subscriptionIds[i]); - if (slot >= SIM_SLOTS) { - Log.w(TAG, "updateInfoCarrier - slot: " + slot); - continue; - } - if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - Log.e(TAG, - "Invalid SIM slot index for subscription: " - + info.subscriptionIds[i]); - continue; + if (info.airplaneMode) { + setVisibility(View.GONE); + } else { + setVisibility(View.VISIBLE); + if (info.anySimReady) { + boolean[] slotSeen = new boolean[SIM_SLOTS]; + if (info.listOfCarriers.length == info.subscriptionIds.length) { + for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) { + int slot = getSlotIndex(info.subscriptionIds[i]); + if (slot >= SIM_SLOTS) { + Log.w(TAG, "updateInfoCarrier - slot: " + slot); + continue; + } + if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + Log.e(TAG, + "Invalid SIM slot index for subscription: " + + info.subscriptionIds[i]); + continue; + } + mInfos[slot].visible = true; + slotSeen[slot] = true; + mCarrierGroups[slot].setCarrierText( + info.listOfCarriers[i].toString().trim()); + mCarrierGroups[slot].setVisibility(View.VISIBLE); } - mInfos[slot].visible = true; - slotSeen[slot] = true; - mCarrierGroups[slot].setCarrierText(info.listOfCarriers[i].toString().trim()); - mCarrierGroups[slot].setVisibility(View.VISIBLE); - } - for (int i = 0; i < SIM_SLOTS; i++) { - if (!slotSeen[i]) { - mInfos[i].visible = false; - mCarrierGroups[i].setVisibility(View.GONE); + for (int i = 0; i < SIM_SLOTS; i++) { + if (!slotSeen[i]) { + mInfos[i].visible = false; + mCarrierGroups[i].setVisibility(View.GONE); + } } + } else { + Log.e(TAG, "Carrier information arrays not of same length"); } } else { - Log.e(TAG, "Carrier information arrays not of same length"); - } - } else { - mInfos[0].visible = false; - mCarrierGroups[0].setCarrierText(info.carrierText); - mCarrierGroups[0].setVisibility(View.VISIBLE); - for (int i = 1; i < SIM_SLOTS; i++) { - mInfos[i].visible = false; - mCarrierGroups[i].setCarrierText(""); - mCarrierGroups[i].setVisibility(View.GONE); + mInfos[0].visible = false; + mCarrierGroups[0].setCarrierText(info.carrierText); + mCarrierGroups[0].setVisibility(View.VISIBLE); + for (int i = 1; i < SIM_SLOTS; i++) { + mInfos[i].visible = false; + mCarrierGroups[i].setCarrierText(""); + mCarrierGroups[i].setVisibility(View.GONE); + } } } handleUpdateState(); 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/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index f69356ea14a0..ce9401cff676 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -830,4 +830,12 @@ public final class NotificationEntry { this.index = index; } } + + /** + * Returns whether the notification is a foreground service. It shows that this is an ongoing + * bubble. + */ + public boolean isForegroundService() { + return (notification.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; + } } 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/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 79bf6b3e49f6..b9cacd14451c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -271,7 +271,12 @@ public class EdgeBackGestureHandler implements DisplayListener { if (x > mEdgeWidth && x < (mDisplaySize.x - mEdgeWidth)) { return false; } - return !mExcludeRegion.contains(x, y); + boolean isInExcludedRegion = mExcludeRegion.contains(x, y); + if (isInExcludedRegion) { + mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1, + false /* isButton */, !mIsOnLeftEdge); + } + return !isInExcludedRegion; } private void onMotionEvent(MotionEvent ev) { 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/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java index 1a9fd5315c32..51ae70b84286 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java @@ -23,9 +23,11 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.google.android.collect.Lists; import com.google.android.collect.Sets; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -62,15 +64,18 @@ class ThemeOverlayManager { static final String OVERLAY_CATEGORY_ICON_LAUNCHER = "android.theme.customization.icon_pack.launcher"; - /* All theme customization categories used by the system. */ - static final Set<String> THEME_CATEGORIES = Sets.newHashSet( - OVERLAY_CATEGORY_COLOR, - OVERLAY_CATEGORY_FONT, + /* + * All theme customization categories used by the system, in order that they should be applied, + * starts with launcher and grouped by target package. + */ + static final List<String> THEME_CATEGORIES = Lists.newArrayList( + OVERLAY_CATEGORY_ICON_LAUNCHER, OVERLAY_CATEGORY_SHAPE, + OVERLAY_CATEGORY_FONT, + OVERLAY_CATEGORY_COLOR, OVERLAY_CATEGORY_ICON_ANDROID, OVERLAY_CATEGORY_ICON_SYSUI, - OVERLAY_CATEGORY_ICON_SETTINGS, - OVERLAY_CATEGORY_ICON_LAUNCHER); + OVERLAY_CATEGORY_ICON_SETTINGS); /* Categories that need to applied to the current user as well as the system user. */ @VisibleForTesting @@ -115,29 +120,30 @@ class ThemeOverlayManager { */ void applyCurrentUserOverlays( Map<String, String> categoryToPackage, Set<UserHandle> userHandles) { - final Map<Boolean, List<String>> categorySplit = THEME_CATEGORIES.stream().collect( - Collectors.partitioningBy((category) -> categoryToPackage.containsKey(category))); - final List<String> overlayCategoriesToEnable = categorySplit.get(true); - final List<String> overlayCategoriesToDisable = categorySplit.get(false); - // Disable all overlays that have not been specified in the user setting. - final List<OverlayInfo> overlays = new ArrayList<>(); - overlayCategoriesToDisable.stream() + final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES); + overlayCategoriesToDisable.removeAll(categoryToPackage.keySet()); + final Set<String> targetPackagesToQuery = overlayCategoriesToDisable.stream() .map(category -> mCategoryToTargetPackage.get(category)) - .collect(Collectors.toSet()) - .forEach(targetPackage -> overlays.addAll(mOverlayManager - .getOverlayInfosForTarget(targetPackage, UserHandle.SYSTEM))); - overlays.stream() + .collect(Collectors.toSet()); + final List<OverlayInfo> overlays = new ArrayList<>(); + targetPackagesToQuery.forEach(targetPackage -> overlays.addAll(mOverlayManager + .getOverlayInfosForTarget(targetPackage, UserHandle.SYSTEM))); + final Map<String, String> overlaysToDisable = overlays.stream() .filter(o -> mTargetPackageToCategories.get(o.targetPackageName).contains(o.category)) .filter(o -> overlayCategoriesToDisable.contains(o.category)) .filter(o -> o.isEnabled()) - .forEach(o -> setEnabled(o.packageName, o.category, userHandles, false)); - - - // Enable all overlays specified in the user setting. - overlayCategoriesToEnable.forEach((category) -> - setEnabled(categoryToPackage.get(category), category, userHandles, true)); + .collect(Collectors.toMap((o) -> o.category, (o) -> o.packageName)); + + // Toggle overlays in the order of THEME_CATEGORIES. + for (String category : THEME_CATEGORIES) { + if (categoryToPackage.containsKey(category)) { + setEnabled(categoryToPackage.get(category), category, userHandles, true); + } else if (overlaysToDisable.containsKey(category)) { + setEnabled(overlaysToDisable.get(category), category, userHandles, false); + } + } } private void setEnabled( diff --git a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java index 45fc7563a5c3..1862ed3a4de8 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java +++ b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java @@ -22,6 +22,9 @@ import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; +import androidx.core.view.ViewCompat; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; + import com.android.keyguard.AlphaOptimizedImageButton; import com.android.systemui.R; @@ -31,7 +34,7 @@ public class CaptionsToggleImageButton extends AlphaOptimizedImageButton { private static final int[] OPTED_OUT_STATE = new int[] { R.attr.optedOut }; private ConfirmedTapListener mConfirmedTapListener; - private boolean mComponentEnabled = false; + private boolean mCaptionsEnabled = false; private boolean mOptedOut = false; private GestureDetector mGestureDetector; @@ -39,16 +42,14 @@ public class CaptionsToggleImageButton extends AlphaOptimizedImageButton { new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { - if (mConfirmedTapListener != null) { - mConfirmedTapListener.onConfirmedTap(); - return true; - } - return false; + return tryToSendTapConfirmedEvent(); } }; public CaptionsToggleImageButton(Context context, AttributeSet attrs) { super(context, attrs); + this.setContentDescription( + getContext().getString(R.string.volume_odi_captions_content_description)); } @Override @@ -66,16 +67,32 @@ public class CaptionsToggleImageButton extends AlphaOptimizedImageButton { return state; } - Runnable setComponentEnabled(boolean isComponentEnabled) { - this.mComponentEnabled = isComponentEnabled; + Runnable setCaptionsEnabled(boolean areCaptionsEnabled) { + this.mCaptionsEnabled = areCaptionsEnabled; + + ViewCompat.replaceAccessibilityAction( + this, + AccessibilityActionCompat.ACTION_CLICK, + mCaptionsEnabled + ? getContext().getString(R.string.volume_odi_captions_hint_disable) + : getContext().getString(R.string.volume_odi_captions_hint_enable), + (view, commandArguments) -> tryToSendTapConfirmedEvent()); - return this.setImageResourceAsync(this.mComponentEnabled + return this.setImageResourceAsync(mCaptionsEnabled ? R.drawable.ic_volume_odi_captions : R.drawable.ic_volume_odi_captions_disabled); } - boolean getComponentEnabled() { - return this.mComponentEnabled; + private boolean tryToSendTapConfirmedEvent() { + if (mConfirmedTapListener != null) { + mConfirmedTapListener.onConfirmedTap(); + return true; + } + return false; + } + + boolean getCaptionsEnabled() { + return this.mCaptionsEnabled; } /** Sets whether or not the current stream has opted out of captions */ diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 509537089bf8..8d9c5a3740b2 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -596,9 +596,9 @@ public class VolumeDialogImpl implements VolumeDialog, } private void updateCaptionsIcon() { - boolean componentEnabled = mController.areCaptionsEnabled(); - if (mODICaptionsIcon.getComponentEnabled() != componentEnabled) { - mHandler.post(mODICaptionsIcon.setComponentEnabled(componentEnabled)); + boolean captionsEnabled = mController.areCaptionsEnabled(); + if (mODICaptionsIcon.getCaptionsEnabled() != captionsEnabled) { + mHandler.post(mODICaptionsIcon.setCaptionsEnabled(captionsEnabled)); } boolean isOptedOut = mController.isCaptionStreamOptedOut(); @@ -878,7 +878,6 @@ public class VolumeDialogImpl implements VolumeDialog, } view.setContentDescription(mContext.getString(currStateResId)); - view.setAccessibilityDelegate(new AccessibilityDelegate() { public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(host, info); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index 8e061cc84396..df534d79f730 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -37,6 +37,7 @@ import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -81,6 +82,8 @@ public class CarrierTextControllerTest extends SysuiTestCase { private ConnectivityManager mConnectivityManager; @Mock private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionManager mSubscriptionManager; private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo; private CarrierTextController mCarrierTextController; @@ -94,6 +97,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { mContext.addMockSystemService(WifiManager.class, mWifiManager); mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager); mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); + mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); mDependency.injectMockDependency(WakefulnessLifecycle.class); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, new Handler(mTestableLooper.getLooper())); @@ -169,6 +173,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -192,6 +197,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION_ROAMING); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = 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/DumpControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt new file mode 100644 index 000000000000..cca35ca39606 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import java.io.FileDescriptor +import java.io.PrintWriter + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class DumpControllerTest : SysuiTestCase() { + + private lateinit var controller: DumpController + @Mock private lateinit var callback1: Dumpable + @Mock private lateinit var callback2: Dumpable + @Mock private lateinit var fd: FileDescriptor + @Mock private lateinit var pw: PrintWriter + private val args = emptyArray<String>() + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + controller = DumpController() +// Debug.waitForDebugger() + } + + @Test + fun testListenerOnlyAddedOnce() { + controller.apply { + addListener(callback1) + addListener(callback1) + } + assertEquals(1, controller.numListeners) + + controller.dump(fd, pw, args) + verify(callback1 /* only once */).dump(fd, pw, args) + } + + @Test + fun testListenersCalledOnDump() { + controller.apply { + addListener(callback1) + addListener(callback2) + } + + controller.dump(fd, pw, args) + + verify(callback1 /* only once */).dump(fd, pw, args) + verify(callback2 /* only once */).dump(fd, pw, args) + } + + @Test + fun testRemoveListener() { + controller.apply { + addListener(callback1) + addListener(callback2) + removeListener(callback1) + } + + controller.dump(fd, pw, args) + + verify(callback1, never()).dump(any(), any(), any()) + verify(callback2 /* only once */).dump(fd, pw, args) + } +} 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/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java index da039a403087..a904704e3ea6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java @@ -51,7 +51,9 @@ import com.google.common.collect.Sets; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.HashMap; @@ -134,6 +136,17 @@ public class ThemeOverlayManagerTest extends SysuiTestCase { } @Test + public void allCategoriesSpecified_enabledInOrder() { + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES); + + InOrder inOrder = Mockito.inOrder(mOverlayManager); + for (String category : THEME_CATEGORIES) { + inOrder.verify(mOverlayManager) + .setEnabledExclusiveInCategory(ALL_CATEGORIES_MAP.get(category), TEST_USER); + } + } + + @Test public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() { mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES); 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 49e7f1de3755..000000000000 --- a/packages/overlays/IconPackFilledLauncherOverlay/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/IconPackFilledLauncherOverlay/res/drawable/ic_corp.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_corp.xml index f7b7f779e32d..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: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" /> + 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 6c9c732af347..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,16 +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: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: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: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" /> + 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/IconPackRoundedLauncherOverlay/res/drawable/ic_wallpaper.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_palette.xml index 880b2abc8752..e9a89ec569f2 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/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 82c2a3197e00..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: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" /> + 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 c4c5eaab72f5..513633bdc57d 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_setting.xml @@ -16,13 +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: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: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" /> + 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 790248ade6ee..4ca296701e6f 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_smartspace_preferences.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_smartspace_preferences.xml @@ -16,10 +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: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" /> + 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="@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="@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 013b40f41cff..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: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" /> + 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: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" /> + 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 4af8a3734d1d..41987590a702 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_warning.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_warning.xml @@ -16,16 +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: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: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: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" /> + 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 7cbf7f1ff0e7..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: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" /> + 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: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" /> + 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: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" /> + 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: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" /> + 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 d04eb1f53c37..000000000000 --- a/packages/overlays/IconPackRoundedLauncherOverlay/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/IconPackRoundedLauncherOverlay/res/drawable/ic_corp.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_corp.xml index ed395433ae5b..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: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" /> + 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 dfa17d6142f4..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,10 +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: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" /> + 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="@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="@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/IconPackFilledLauncherOverlay/res/drawable/ic_wallpaper.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_palette.xml index e58c7b8f1496..964955bc96ca 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/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 22401a1a1cca..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: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" /> + 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 b4f0478f48b5..6ff3144b9a73 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_setting.xml @@ -16,10 +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: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" /> + 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="@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 57ae91f89839..3cc9e51c21cb 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_smartspace_preferences.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_smartspace_preferences.xml @@ -16,16 +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: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: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: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" /> + 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 dc3bd95eb624..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: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" /> + 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: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" /> + 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 184714c8e4d3..63d7b78f76c2 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_warning.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_warning.xml @@ -16,10 +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: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" /> + 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="@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="@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 ca09fc9e4caf..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: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" /> + 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: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" /> + 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: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" /> + 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: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" /> + 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/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml index 86fd47bfc63f..80fd45924fc9 100644 --- a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml +++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml @@ -34,7 +34,7 @@ <dimen name="config_backGestureInset">20dp</dimen> <!-- Controls whether the navbar needs a scrim with - {@link Window#setEnsureNavigationBarContrastWhenTransparent}. --> + {@link Window#setEnsuringNavigationBarContrastWhenTransparent}. --> <bool name="config_navBarNeedsScrim">false</bool> </resources> 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/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 447bd8c237dd..03f21498766d 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -566,10 +566,6 @@ public class UserBackupManagerService { // require frequent starting and stopping. mConstants.start(); - // Set up the various sorts of package tracking we do - mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); - initPackageTracking(); - // Build our mapping of uid to backup client services. This implicitly // schedules a backup pass on the Package Manager metadata the first // time anything needs to be backed up. @@ -589,6 +585,10 @@ public class UserBackupManagerService { // Power management mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId); + + // Set up the various sorts of package tracking we do + mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); + initPackageTracking(); } void initializeBackupEnableState() { @@ -744,6 +744,11 @@ public class UserBackupManagerService { return mDataDir; } + @VisibleForTesting + BroadcastReceiver getPackageTrackingReceiver() { + return mBroadcastReceiver; + } + @Nullable public DataChangedJournal getJournal() { return mJournal; diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java index 593bb2c41587..35dfccf32924 100644 --- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java @@ -23,22 +23,20 @@ import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_A import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.Nullable; -import android.app.AppGlobals; import android.app.backup.BackupTransport; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.content.pm.SigningInfo; -import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.backup.IBackupTransport; import com.android.internal.util.ArrayUtils; +import com.android.server.LocalServices; import com.android.server.backup.transport.TransportClient; import com.google.android.collect.Sets; @@ -67,12 +65,13 @@ public class AppBackupUtils { * </ol> */ public static boolean appIsEligibleForBackup(ApplicationInfo app, int userId) { - return appIsEligibleForBackup(app, AppGlobals.getPackageManager(), userId); + return appIsEligibleForBackup( + app, LocalServices.getService(PackageManagerInternal.class), userId); } @VisibleForTesting - static boolean appIsEligibleForBackup(ApplicationInfo app, - IPackageManager packageManager, int userId) { + static boolean appIsEligibleForBackup( + ApplicationInfo app, PackageManagerInternal packageManager, int userId) { // 1. their manifest states android:allowBackup="false" if ((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { return false; @@ -108,9 +107,9 @@ public class AppBackupUtils { /** * Returns whether an app is eligible for backup at runtime. That is, the app has to: * <ol> - * <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, PackageManager)} + * <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, int)} * <li>Return false for {@link #appIsStopped(ApplicationInfo)} - * <li>Return false for {@link #appIsDisabled(ApplicationInfo, PackageManager)} + * <li>Return false for {@link #appIsDisabled(ApplicationInfo, int)} * <li>Be eligible for the transport via * {@link BackupTransport#isAppEligibleForBackup(PackageInfo, boolean)} * </ol> @@ -149,19 +148,13 @@ public class AppBackupUtils { /** Avoid backups of 'disabled' apps. */ static boolean appIsDisabled(ApplicationInfo app, int userId) { - return appIsDisabled(app, AppGlobals.getPackageManager(), userId); + return appIsDisabled(app, LocalServices.getService(PackageManagerInternal.class), userId); } @VisibleForTesting - static boolean appIsDisabled(ApplicationInfo app, - IPackageManager packageManager, int userId) { - int enabledSetting; - try { - enabledSetting = packageManager.getApplicationEnabledSetting(app.packageName, userId); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to get application enabled setting: " + e); - return false; - } + static boolean appIsDisabled( + ApplicationInfo app, PackageManagerInternal packageManager, int userId) { + int enabledSetting = packageManager.getApplicationEnabledState(app.packageName, userId); switch (enabledSetting) { case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 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/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 3dc8af1c06c5..ae0047f41d74 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -730,6 +730,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub { ActivityManager.getService().notifyCleartextNetwork(uid, HexDump.hexStringToByteArray(hex)); } + + @Override + public int getInterfaceVersion() { + return INetdUnsolicitedEventListener.VERSION; + } } // 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/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index e64ab78d1ed2..40bf7bccff72 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -60,6 +60,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { @NonNull private static final String TAG = TestNetworkService.class.getSimpleName(); @NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK"; @NonNull private static final String TEST_TUN_PREFIX = "testtun"; + @NonNull private static final String TEST_TAP_PREFIX = "testtap"; @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger(); @NonNull private final Context mContext; @@ -70,7 +71,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { @NonNull private final Handler mHandler; // Native method stubs - private static native int jniCreateTun(@NonNull String iface); + private static native int jniCreateTunTap(boolean isTun, @NonNull String iface); @VisibleForTesting protected TestNetworkService( @@ -85,23 +86,23 @@ class TestNetworkService extends ITestNetworkManager.Stub { } /** - * Create a TUN interface with the given interface name and link addresses + * Create a TUN or TAP interface with the given interface name and link addresses * - * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the - * TUN interface. + * <p>This method will return the FileDescriptor to the interface. Close it to tear down the + * interface. */ - @Override - public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { + private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) { enforceTestNetworkPermissions(mContext); checkNotNull(linkAddrs, "missing linkAddrs"); - String iface = TEST_TUN_PREFIX + sTestTunIndex.getAndIncrement(); + String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX; + String iface = ifacePrefix + sTestTunIndex.getAndIncrement(); return Binder.withCleanCallingIdentity( () -> { try { ParcelFileDescriptor tunIntf = - ParcelFileDescriptor.adoptFd(jniCreateTun(iface)); + ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface)); for (LinkAddress addr : linkAddrs) { mNetd.interfaceAddAddress( iface, @@ -116,6 +117,28 @@ class TestNetworkService extends ITestNetworkManager.Stub { }); } + /** + * Create a TUN interface with the given interface name and link addresses + * + * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the + * TUN interface. + */ + @Override + public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { + return createInterface(true, linkAddrs); + } + + /** + * Create a TAP interface with the given interface name + * + * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the + * TAP interface. + */ + @Override + public TestNetworkInterface createTapInterface() { + return createInterface(false, new LinkAddress[0]); + } + // Tracker for TestNetworkAgents @GuardedBy("mTestNetworkTracker") @NonNull @@ -310,7 +333,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { public void teardownTestNetwork(int netId) { enforceTestNetworkPermissions(mContext); - TestNetworkAgent agent; + final TestNetworkAgent agent; synchronized (mTestNetworkTracker) { agent = mTestNetworkTracker.get(netId); } @@ -325,14 +348,10 @@ class TestNetworkService extends ITestNetworkManager.Stub { agent.teardown(); } - // STOPSHIP: Change this back to android.Manifest.permission.MANAGE_TEST_NETWORKS - private static final String PERMISSION_NAME = "dummy"; + private static final String PERMISSION_NAME = + android.Manifest.permission.MANAGE_TEST_NETWORKS; public static void enforceTestNetworkPermissions(@NonNull Context context) { - // STOPSHIP: Re-enable these checks. Disabled until adoptShellPermissionIdentity() can be - // called from CTS test code. - if (false) { - context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService"); - } + context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService"); } } 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 d965434fb798..0271354b3fff 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2118,6 +2118,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) { @@ -2176,8 +2182,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); @@ -2558,7 +2564,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) { @@ -2589,10 +2595,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); } } @@ -2600,7 +2607,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 7d9cf1432e91..cdcd9e1ad58c 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) { @@ -6916,9 +6918,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 " @@ -7639,7 +7642,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(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); } @@ -7660,9 +7665,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; @@ -13612,7 +13617,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! @@ -13953,9 +13959,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; @@ -18166,8 +18175,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/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index d1379b669563..cba9674d7360 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -826,7 +826,7 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } } - process = getNextArg(); + process = getNextArgRequired(); } else { // Compatibility with old syntax: process is specified first. process = cmd; @@ -2998,15 +2998,22 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" start: start tracing IPC transactions."); pw.println(" stop: stop tracing IPC transactions and dump the results to file."); pw.println(" --dump-file <FILE>: Specify the file the trace should be dumped to."); - pw.println(" profile [start|stop] [--user <USER_ID> current] [--sampling INTERVAL]"); - pw.println(" [--streaming] <PROCESS> <FILE>"); - pw.println(" Start and stop profiler on a process. The given <PROCESS> argument"); + pw.println(" profile start [--user <USER_ID> current]"); + pw.println(" [--sampling INTERVAL | --streaming] <PROCESS> <FILE>"); + pw.println(" Start profiler on a process. The given <PROCESS> argument"); pw.println(" may be either a process name or pid. Options are:"); pw.println(" --user <USER_ID> | current: When supplying a process name,"); - pw.println(" specify user of process to profile; uses current user if not specified."); + pw.println(" specify user of process to profile; uses current user if not"); + pw.println(" specified."); pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds"); - pw.println(" between samples"); - pw.println(" --streaming: stream the profiling output to the specified file"); + pw.println(" between samples."); + pw.println(" --streaming: stream the profiling output to the specified file."); + pw.println(" profile stop [--user <USER_ID> current] <PROCESS>"); + pw.println(" Stop profiler on a process. The given <PROCESS> argument"); + pw.println(" may be either a process name or pid. Options are:"); + pw.println(" --user <USER_ID> | current: When supplying a process name,"); + pw.println(" specify user of process to profile; uses current user if not"); + pw.println(" specified."); pw.println(" dumpheap [--user <USER_ID> current] [-n] [-g] <PROCESS> <FILE>"); pw.println(" Dump the heap of a process. The given <PROCESS> argument may"); pw.println(" be either a process name or pid. Options are:"); diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 438a367a8280..ee9b5614584f 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1624,7 +1624,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 48186f82c5ca..316368a52ce2 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -62,6 +62,7 @@ import android.os.AppZygote; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.GraphicsEnvironment; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -453,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) { @@ -469,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; } @@ -703,6 +704,13 @@ public final class ProcessList { return prefix + "+" + Integer.toString(diff); } + private static boolean shouldUseSystemGraphicsDriver(Context context, Bundle coreSettings, + ApplicationInfo applicationInfo) { + final boolean shouldUseGameDriver = + GraphicsEnvironment.shouldUseGameDriver(context, coreSettings, applicationInfo); + return !shouldUseGameDriver; + } + public static String makeOomAdjString(int setAdj, boolean compact) { if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { return buildOomTag("cch", "cch", " ", setAdj, @@ -1419,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; @@ -1617,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) { @@ -1636,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, @@ -1646,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()); @@ -1664,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) { @@ -1685,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); @@ -1719,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); @@ -1745,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); } @@ -1773,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) { @@ -1783,18 +1811,21 @@ public final class ProcessList { final StorageManagerInternal storageManagerInternal = LocalServices.getService(StorageManagerInternal.class); final String sandboxId = storageManagerInternal.getSandboxId(app.info.packageName); + final boolean useSystemGraphicsDriver = shouldUseSystemGraphicsDriver(mService.mContext, + mService.mCoreSettingsObserver.getCoreSettingsLocked(), app.info); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + 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, app.info.dataDir, null, app.info.packageName, packageNames, sandboxId, - new String[] {PROC_START_SEQ_IDENT + app.startSeq}); - } else if (hostingType.equals("app_zygote")) { + new String[] {PROC_START_SEQ_IDENT + app.startSeq}, + useSystemGraphicsDriver); + } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); startResult = appZygote.getProcess().start(entryPoint, @@ -1802,14 +1833,16 @@ public final class ProcessList { app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, packageNames, sandboxId, /*useUnspecializedAppProcessPool=*/ false, - new String[] {PROC_START_SEQ_IDENT + app.startSeq}); + new String[] {PROC_START_SEQ_IDENT + app.startSeq}, + useSystemGraphicsDriver); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, packageNames, sandboxId, - new String[] {PROC_START_SEQ_IDENT + app.startSeq}); + new String[] {PROC_START_SEQ_IDENT + app.startSeq}, + useSystemGraphicsDriver); } checkSlow(startTime, "startProcess: returned from zygote!"); return startResult; @@ -1819,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(); @@ -1903,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); @@ -1940,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; } @@ -2002,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, @@ -2031,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); @@ -2295,24 +2322,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 1fc82abc6246..49930c1f4d62 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(OomAdjuster.OOM_ADJ_REASON_ACTIVITY); } @@ -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..c573332235d8 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -114,8 +114,10 @@ import java.util.ArrayList; // All post* methods are asynchronous /*package*/ void onSystemReady() { - synchronized (mDeviceStateLock) { - mBtHelper.onSystemReady(); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.onSystemReady(); + } } } @@ -151,8 +153,10 @@ import java.util.ArrayList; * @param intent */ /*package*/ void receiveBtEvent(@NonNull Intent intent) { - synchronized (mDeviceStateLock) { - mBtHelper.receiveBtEvent(intent); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.receiveBtEvent(intent); + } } } @@ -350,13 +354,19 @@ import java.util.ArrayList; sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device); } + @GuardedBy("mSetModeLock") /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode, @NonNull String eventSource) { - mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource); + synchronized (mDeviceStateLock) { + mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource); + } } + @GuardedBy("mSetModeLock") /*package*/ void stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource) { - mBtHelper.stopBluetoothScoForClient(cb, eventSource); + synchronized (mDeviceStateLock) { + mBtHelper.stopBluetoothScoForClient(cb, eventSource); + } } //--------------------------------------------------------------------- @@ -406,6 +416,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) { @@ -475,6 +489,10 @@ import java.util.ArrayList; hearingAidProfile); } + /*package*/ void postScoClientDied(Object obj) { + sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj); + } + //--------------------------------------------------------------------- // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) // only call from a "handle"* method or "on"* method @@ -704,8 +722,10 @@ import java.util.ArrayList; } break; case MSG_BT_HEADSET_CNCT_FAILED: - synchronized (mDeviceStateLock) { - mBtHelper.resetBluetoothSco(); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.resetBluetoothSco(); + } } break; case MSG_IL_BTA2DP_DOCK_TIMEOUT: @@ -738,8 +758,17 @@ import java.util.ArrayList; } break; case MSG_I_DISCONNECT_BT_SCO: - synchronized (mDeviceStateLock) { - mBtHelper.disconnectBluetoothSco(msg.arg1); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.disconnectBluetoothSco(msg.arg1); + } + } + break; + case MSG_L_SCOCLIENT_DIED: + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.scoClientDied(msg.arg1); + } } break; case MSG_TOGGLE_HDMI: @@ -770,8 +799,10 @@ import java.util.ArrayList; } break; case MSG_DISCONNECT_BT_HEADSET: - synchronized (mDeviceStateLock) { - mBtHelper.disconnectHeadset(); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.disconnectHeadset(); + } } break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: @@ -790,8 +821,10 @@ import java.util.ArrayList; } break; case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: - synchronized (mDeviceStateLock) { - mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + } } break; case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: { @@ -888,6 +921,8 @@ import java.util.ArrayList; private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28; // process external command to (dis)connect or change active A2DP device private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT = 29; + // a ScoClient died in BtHelper + private static final int MSG_L_SCOCLIENT_DIED = 30; private static boolean isMessageHandledUnderWakelock(int msgId) { 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 d58888a7c67b..d30a9d2b158e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -90,9 +90,8 @@ import android.media.audiofx.AudioEffect; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicyConfig; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; import android.media.audiopolicy.AudioVolumeGroup; -import android.media.audiopolicy.AudioVolumeGroups; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionManager; @@ -281,11 +280,6 @@ public class AudioService extends IAudioService.Stub private SettingsObserver mSettingsObserver; - /** @see AudioProductStrategies */ - private static AudioProductStrategies sAudioProductStrategies; - /** @see AudioVolumeGroups */ - private static AudioVolumeGroups sAudioVolumeGroups; - private int mMode = AudioSystem.MODE_NORMAL; // protects mRingerMode private final Object mSettingsLock = new Object(); @@ -636,19 +630,17 @@ public class AudioService extends IAudioService.Stub mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator(); - sAudioProductStrategies = new AudioProductStrategies(); - sAudioVolumeGroups = new AudioVolumeGroups(); - // Initialize volume // Priority 1 - Android Property // Priority 2 - Audio Policy Service // Priority 3 - Default Value - if (sAudioProductStrategies.size() > 0) { + if (AudioProductStrategy.getAudioProductStrategies().size() > 0) { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { AudioAttributes attr = - sAudioProductStrategies.getAudioAttributesForLegacyStreamType(streamType); + AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( + streamType); int maxVolume = AudioSystem.getMaxVolumeIndexForAttributes(attr); if (maxVolume != -1) { MAX_STREAM_VOLUME[streamType] = maxVolume; @@ -1023,19 +1015,21 @@ public class AudioService extends IAudioService.Stub } /** - * @return the {@link android.media.audiopolicy.AudioProductStrategies} discovered from the + * @return the {@link android.media.audiopolicy.AudioProductStrategy} discovered from the * platform configuration file. */ - public @NonNull AudioProductStrategies getAudioProductStrategies() { - return sAudioProductStrategies; + @NonNull + public List<AudioProductStrategy> getAudioProductStrategies() { + return AudioProductStrategy.getAudioProductStrategies(); } /** - * @return the {@link android.media.audiopolicy.AudioVolumeGroups} discovered from the + * @return the List of {@link android.media.audiopolicy.AudioVolumeGroup} discovered from the * platform configuration file. */ - public @NonNull AudioVolumeGroups listAudioVolumeGroups() { - return sAudioVolumeGroups; + @NonNull + public List<AudioVolumeGroup> getAudioVolumeGroups() { + return AudioVolumeGroup.getAudioVolumeGroups(); } private void checkAllAliasStreamVolumes() { @@ -1529,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. @@ -1947,15 +1943,15 @@ public class AudioService extends IAudioService.Stub enforceModifyAudioRoutingPermission(); Preconditions.checkNotNull(attr, "attr must not be null"); // @todo not hold the caller context, post message - int stream = sAudioProductStrategies.getLegacyStreamTypeForAudioAttributes(attr); + int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr); final int device = getDeviceForStream(stream); int oldIndex = AudioSystem.getVolumeIndexForAttributes(attr, device); AudioSystem.setVolumeIndexForAttributes(attr, index, device); - final int volumeGroup = sAudioProductStrategies.getVolumeGroupIdForAttributes(attr); - final AudioVolumeGroup avg = sAudioVolumeGroups.getById(volumeGroup); + final int volumeGroup = getVolumeGroupIdForAttributes(attr); + final AudioVolumeGroup avg = getAudioVolumeGroupById(volumeGroup); if (avg == null) { return; } @@ -1965,11 +1961,23 @@ public class AudioService extends IAudioService.Stub } } + @Nullable + private AudioVolumeGroup getAudioVolumeGroupById(int volumeGroupId) { + for (final AudioVolumeGroup avg : AudioVolumeGroup.getAudioVolumeGroups()) { + if (avg.getId() == volumeGroupId) { + return avg; + } + } + + Log.e(TAG, ": invalid volume group id: " + volumeGroupId + " requested"); + return null; + } + /** @see AudioManager#getVolumeIndexForAttributes(attr) */ public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { enforceModifyAudioRoutingPermission(); Preconditions.checkNotNull(attr, "attr must not be null"); - int stream = sAudioProductStrategies.getLegacyStreamTypeForAudioAttributes(attr); + int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr); final int device = getDeviceForStream(stream); return AudioSystem.getVolumeIndexForAttributes(attr, device); @@ -2144,6 +2152,32 @@ public class AudioService extends IAudioService.Stub sendVolumeUpdate(streamType, oldIndex, index, flags); } + + + private int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { + Preconditions.checkNotNull(attributes, "attributes must not be null"); + int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes); + if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { + return volumeGroupId; + } + // The default volume group is the one hosted by default product strategy, i.e. + // supporting Default Attributes + return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); + } + + private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) { + Preconditions.checkNotNull(attributes, "attributes must not be null"); + for (final AudioProductStrategy productStrategy : + AudioProductStrategy.getAudioProductStrategies()) { + int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes); + if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { + return volumeGroupId; + } + } + return AudioVolumeGroup.DEFAULT_VOLUME_GROUP; + } + + // No ringer or zen muted stream volumes can be changed unless it'll exit dnd private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) { switch (mNm.getZenMode()) { @@ -3450,7 +3484,9 @@ public class AudioService extends IAudioService.Stub !mSystemReady) { return; } - mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource); + synchronized (mDeviceBroker.mSetModeLock) { + mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource); + } } /** @see AudioManager#stopBluetoothSco() */ @@ -3462,7 +3498,9 @@ public class AudioService extends IAudioService.Stub final String eventSource = new StringBuilder("stopBluetoothSco()") .append(") from u/pid:").append(Binder.getCallingUid()).append("/") .append(Binder.getCallingPid()).toString(); - mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource); + synchronized (mDeviceBroker.mSetModeLock) { + mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource); + } } @@ -5546,6 +5584,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) || @@ -6288,6 +6330,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); } @@ -6628,6 +6675,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/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 2d9156b8782e..332ff362392a 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -36,6 +36,8 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; @@ -163,6 +165,8 @@ public class BtHelper { //---------------------------------------------------------------------- // Interface for AudioDeviceBroker + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onSystemReady() { mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR; resetBluetoothSco(); @@ -231,6 +235,8 @@ public class BtHelper { return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType()); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void receiveBtEvent(Intent intent) { final String action = intent.getAction(); if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) { @@ -317,6 +323,8 @@ public class BtHelper { * * @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept */ + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void disconnectBluetoothSco(int exceptPid) { checkScoAudioState(); if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) { @@ -325,6 +333,8 @@ public class BtHelper { clearAllScoClients(exceptPid, true); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void startBluetoothScoForClient(IBinder cb, int scoAudioMode, @NonNull String eventSource) { ScoClient client = getScoClient(cb, true); @@ -344,6 +354,8 @@ public class BtHelper { Binder.restoreCallingIdentity(ident); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void stopBluetoothScoForClient(IBinder cb, @NonNull String eventSource) { ScoClient client = getScoClient(cb, false); @@ -401,6 +413,8 @@ public class BtHelper { mDeviceBroker.postDisconnectHearingAid(); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void resetBluetoothSco() { clearAllScoClients(0, false); mScoAudioState = SCO_STATE_INACTIVE; @@ -409,6 +423,8 @@ public class BtHelper { mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco"); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void disconnectHeadset() { setBtScoActiveDevice(null); mBluetoothHeadset = null; @@ -454,6 +470,8 @@ public class BtHelper { /*eventSource*/ "mBluetoothProfileServiceListener"); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) { // Discard timeout message mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); @@ -540,6 +558,9 @@ public class BtHelper { return result; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") private void setBtScoActiveDevice(BluetoothDevice btDevice) { Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice); final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice; @@ -621,6 +642,20 @@ public class BtHelper { }; //---------------------------------------------------------------------- + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + /*package*/ synchronized void scoClientDied(Object obj) { + final ScoClient client = (ScoClient) obj; + Log.w(TAG, "SCO client died"); + int index = mScoClients.indexOf(client); + if (index < 0) { + Log.w(TAG, "unregistered SCO client died"); + } else { + client.clearCount(true); + mScoClients.remove(client); + } + } + private class ScoClient implements IBinder.DeathRecipient { private IBinder mCb; // To be notified of client's death private int mCreatorPid; @@ -634,21 +669,14 @@ public class BtHelper { @Override public void binderDied() { - // this is the only place the implementation of ScoClient needs to be synchronized - // on the instance, as all other methods are directly or indirectly called from - // package-private methods, which are synchronized - synchronized (BtHelper.this) { - Log.w(TAG, "SCO client died"); - int index = mScoClients.indexOf(this); - if (index < 0) { - Log.w(TAG, "unregistered SCO client died"); - } else { - clearCount(true); - mScoClients.remove(this); - } - } + // process this from DeviceBroker's message queue to take the right locks since + // this event can impact SCO mode and requires querying audio mode stack + mDeviceBroker.postScoClientDied(this); } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") void incCount(int scoAudioMode) { requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode); if (mStartcount == 0) { @@ -663,6 +691,9 @@ public class BtHelper { mStartcount++; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") void decCount() { if (mStartcount == 0) { Log.w(TAG, "ScoClient.decCount() already 0"); @@ -679,6 +710,9 @@ public class BtHelper { } } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + // @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") void clearCount(boolean stopSco) { if (mStartcount != 0) { try { @@ -714,6 +748,9 @@ public class BtHelper { return count; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") private void requestScoState(int state, int scoAudioMode) { checkScoAudioState(); int clientCount = totalCount(); @@ -728,74 +765,71 @@ public class BtHelper { broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); // Accept SCO audio activation only in NORMAL audio mode or if the mode is // currently controlled by the same client process. - // TODO do not sync that way, see b/123769055 - synchronized (mDeviceBroker.mSetModeLock) { - int modeOwnerPid = mDeviceBroker.getSetModeDeathHandlers().isEmpty() - ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid(); - if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) { - Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid " - + modeOwnerPid + " != creatorPid " + mCreatorPid); - broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - return; - } - switch (mScoAudioState) { - case SCO_STATE_INACTIVE: - mScoAudioMode = scoAudioMode; - if (scoAudioMode == SCO_MODE_UNDEFINED) { - mScoAudioMode = SCO_MODE_VIRTUAL_CALL; - if (mBluetoothHeadsetDevice != null) { - mScoAudioMode = Settings.Global.getInt( - mDeviceBroker.getContentResolver(), - "bluetooth_sco_channel_" - + mBluetoothHeadsetDevice.getAddress(), - SCO_MODE_VIRTUAL_CALL); - if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) { - mScoAudioMode = SCO_MODE_VIRTUAL_CALL; - } - } - } - if (mBluetoothHeadset == null) { - if (getBluetoothHeadset()) { - mScoAudioState = SCO_STATE_ACTIVATE_REQ; - } else { - Log.w(TAG, "requestScoState: getBluetoothHeadset failed during" - + " connection, mScoAudioMode=" + mScoAudioMode); - broadcastScoConnectionState( - AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + int modeOwnerPid = mDeviceBroker.getSetModeDeathHandlers().isEmpty() + ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid(); + if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) { + Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid " + + modeOwnerPid + " != creatorPid " + mCreatorPid); + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + return; + } + switch (mScoAudioState) { + case SCO_STATE_INACTIVE: + mScoAudioMode = scoAudioMode; + if (scoAudioMode == SCO_MODE_UNDEFINED) { + mScoAudioMode = SCO_MODE_VIRTUAL_CALL; + if (mBluetoothHeadsetDevice != null) { + mScoAudioMode = Settings.Global.getInt( + mDeviceBroker.getContentResolver(), + "bluetooth_sco_channel_" + + mBluetoothHeadsetDevice.getAddress(), + SCO_MODE_VIRTUAL_CALL); + if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) { + mScoAudioMode = SCO_MODE_VIRTUAL_CALL; } - break; - } - if (mBluetoothHeadsetDevice == null) { - Log.w(TAG, "requestScoState: no active device while connecting," - + " mScoAudioMode=" + mScoAudioMode); - broadcastScoConnectionState( - AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - break; } - if (connectBluetoothScoAudioHelper(mBluetoothHeadset, - mBluetoothHeadsetDevice, mScoAudioMode)) { - mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + } + if (mBluetoothHeadset == null) { + if (getBluetoothHeadset()) { + mScoAudioState = SCO_STATE_ACTIVATE_REQ; } else { - Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice - + " failed, mScoAudioMode=" + mScoAudioMode); + Log.w(TAG, "requestScoState: getBluetoothHeadset failed during" + + " connection, mScoAudioMode=" + mScoAudioMode); broadcastScoConnectionState( AudioManager.SCO_AUDIO_STATE_DISCONNECTED); } break; - case SCO_STATE_DEACTIVATING: - mScoAudioState = SCO_STATE_ACTIVATE_REQ; + } + if (mBluetoothHeadsetDevice == null) { + Log.w(TAG, "requestScoState: no active device while connecting," + + " mScoAudioMode=" + mScoAudioMode); + broadcastScoConnectionState( + AudioManager.SCO_AUDIO_STATE_DISCONNECTED); break; - case SCO_STATE_DEACTIVATE_REQ: + } + if (connectBluetoothScoAudioHelper(mBluetoothHeadset, + mBluetoothHeadsetDevice, mScoAudioMode)) { mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; - broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); - break; - default: - Log.w(TAG, "requestScoState: failed to connect in state " - + mScoAudioState + ", scoAudioMode=" + scoAudioMode); - broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - break; + } else { + Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice + + " failed, mScoAudioMode=" + mScoAudioMode); + broadcastScoConnectionState( + AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + } + break; + case SCO_STATE_DEACTIVATING: + mScoAudioState = SCO_STATE_ACTIVATE_REQ; + break; + case SCO_STATE_DEACTIVATE_REQ: + mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); + break; + default: + Log.w(TAG, "requestScoState: failed to connect in state " + + mScoAudioState + ", scoAudioMode=" + scoAudioMode); + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + break; - } } } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { switch (mScoAudioState) { @@ -906,6 +940,9 @@ public class BtHelper { return null; } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") + @GuardedBy("BtHelper.this") private void clearAllScoClients(int exceptPid, boolean stopSco) { ScoClient savedClient = null; for (ScoClient cl : mScoClients) { 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 f7278d2601c3..91da7af44f0a 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -120,8 +120,8 @@ public abstract class AuthenticationClient extends ClientMonitor { @Override public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> token) { - super.logOnAuthenticated(authenticated, mRequireConfirmation, getTargetUserId(), - isBiometricPrompt()); + super.logOnAuthenticated(getContext(), authenticated, mRequireConfirmation, + getTargetUserId(), isBiometricPrompt()); final BiometricServiceBase.ServiceListener listener = getListener(); @@ -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/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 153133a6c669..4c59e608398c 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -1054,7 +1054,8 @@ public class BiometricService extends SystemService { BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, mCurrentAuthSession.mRequireConfirmation, StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED, - latency); + latency, + Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId)); } else { int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON @@ -1077,7 +1078,8 @@ public class BiometricService extends SystemService { BiometricsProtoEnums.ACTION_AUTHENTICATE, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, error, - 0 /* vendorCode */); + 0 /* vendorCode */, + Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId)); } } diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java index 18c2edc086dc..3f856d3e8eb2 100644 --- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java +++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java @@ -1231,6 +1231,7 @@ public abstract class BiometricServiceBase extends SystemService if (mPendingClient != null) { Slog.d(getTag(), "Enumerate finished, starting pending client"); startClient(mPendingClient, false /* initiatedByClient */); + mPendingClient = null; } } } diff --git a/services/core/java/com/android/server/biometrics/ClientMonitor.java b/services/core/java/com/android/server/biometrics/ClientMonitor.java index 87b9eaaa9cbb..006558080ef0 100644 --- a/services/core/java/com/android/server/biometrics/ClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/ClientMonitor.java @@ -157,7 +157,7 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D * @return true if client should be removed */ public boolean onAcquired(int acquiredInfo, int vendorCode) { - super.logOnAcquired(acquiredInfo, vendorCode, getTargetUserId()); + super.logOnAcquired(mContext, acquiredInfo, vendorCode, getTargetUserId()); if (DEBUG) Slog.v(getLogTag(), "Acquired: " + acquiredInfo + " " + vendorCode); try { if (mListener != null) { @@ -182,7 +182,7 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D * @return true if client should be removed */ public boolean onError(long deviceId, int error, int vendorCode) { - super.logOnError(error, vendorCode, getTargetUserId()); + super.logOnError(mContext, error, vendorCode, getTargetUserId()); try { if (mListener != null) { mListener.onError(deviceId, error, vendorCode, getCookie()); diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java index b0577cd79ac4..9c040884772c 100644 --- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java +++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java @@ -16,6 +16,7 @@ package com.android.server.biometrics; +import android.content.Context; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.face.FaceManager; @@ -61,7 +62,8 @@ public abstract class LoggableMonitor { return BiometricsProtoEnums.CLIENT_UNKNOWN; } - protected final void logOnAcquired(int acquiredInfo, int vendorCode, int targetUserId) { + protected final void logOnAcquired(Context context, int acquiredInfo, int vendorCode, + int targetUserId) { if (statsModality() == BiometricsProtoEnums.MODALITY_FACE) { if (acquiredInfo == FaceManager.FACE_ACQUIRED_START) { mFirstAcquireTimeMs = System.currentTimeMillis(); @@ -87,10 +89,11 @@ public abstract class LoggableMonitor { statsAction(), statsClient(), acquiredInfo, - 0 /* vendorCode */); // Don't log vendorCode for now + 0 /* vendorCode */, // Don't log vendorCode for now + Utils.isDebugEnabled(context, targetUserId)); } - protected final void logOnError(int error, int vendorCode, int targetUserId) { + protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) { if (DEBUG) { Slog.v(TAG, "Error! Modality: " + statsModality() + ", User: " + targetUserId @@ -107,11 +110,12 @@ public abstract class LoggableMonitor { statsAction(), statsClient(), error, - vendorCode); + vendorCode, + Utils.isDebugEnabled(context, targetUserId)); } - protected final void logOnAuthenticated(boolean authenticated, boolean requireConfirmation, - int targetUserId, boolean isBiometricPrompt) { + protected final void logOnAuthenticated(Context context, boolean authenticated, + boolean requireConfirmation, int targetUserId, boolean isBiometricPrompt) { int authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__UNKNOWN; if (!authenticated) { authState = StatsLog.BIOMETRIC_AUTHENTICATED__STATE__REJECTED; @@ -148,7 +152,8 @@ public abstract class LoggableMonitor { statsClient(), requireConfirmation, authState, - latency); + latency, + Utils.isDebugEnabled(context, targetUserId)); } protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) { diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java new file mode 100644 index 000000000000..5544bede92f2 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -0,0 +1,36 @@ +/* + * 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.biometrics; + +import android.content.Context; +import android.os.Build; +import android.provider.Settings; + +public class Utils { + public static boolean isDebugEnabled(Context context, int targetUserId) { + if (!(Build.IS_ENG || Build.IS_USERDEBUG)) { + return false; + } + + if (Settings.Secure.getIntForUser(context.getContentResolver(), + Settings.Secure.BIOMETRIC_DEBUG_ENABLED, 0, + targetUserId) == 0) { + return false; + } + return 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 aa52621d044d..e218c6b399a2 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -42,14 +42,13 @@ import android.os.Binder; import android.os.Build; import android.os.Environment; import android.os.IBinder; +import android.os.NativeHandle; import android.os.RemoteException; import android.os.SELinux; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; -import android.service.restricted_image.RestrictedImageProto; -import android.service.restricted_image.RestrictedImageSetProto; -import android.service.restricted_image.RestrictedImagesDumpProto; +import android.provider.Settings; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -70,8 +69,11 @@ import org.json.JSONObject; import java.io.File; import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -286,8 +288,8 @@ public class FaceService extends BiometricServiceBase { final long ident = Binder.clearCallingIdentity(); try { - if (args.length == 1 && "--restricted_image".equals(args[0])) { - dumpRestrictedImage(fd); + if (args.length > 1 && "--hal".equals(args[0])) { + dumpHal(fd, Arrays.copyOfRange(args, 1, args.length, args.getClass())); } else if (args.length > 0 && "--proto".equals(args[0])) { dumpProto(fd); } else { @@ -546,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"); } @@ -1078,7 +1081,7 @@ public class FaceService extends BiometricServiceBase { mCryptoPerformanceMap.clear(); } - private void dumpRestrictedImage(FileDescriptor fd) { + private void dumpHal(FileDescriptor fd, String[] args) { // WARNING: CDD restricts image data from leaving TEE unencrypted on // production devices: // [C-1-10] MUST not allow unencrypted access to identifiable biometric @@ -1099,59 +1102,28 @@ public class FaceService extends BiometricServiceBase { return; } - final ProtoOutputStream proto = new ProtoOutputStream(fd); - - final long setToken = proto.start(RestrictedImagesDumpProto.SETS); - - // Name of the service - proto.write(RestrictedImageSetProto.CATEGORY, "face"); - - // Individual images - for (int i = 0; i < 5; i++) { - final long imageToken = proto.start(RestrictedImageSetProto.IMAGES); - proto.write(RestrictedImageProto.MIME_TYPE, "image/png"); - proto.write(RestrictedImageProto.IMAGE_DATA, new byte[] { - // png image data - -119, 80, 78, 71, 13, 10, 26, 10, - 0, 0, 0, 13, 73, 72, 68, 82, - 0, 0, 0, 100, 0, 0, 0, 100, - 1, 3, 0, 0, 0, 74, 44, 7, - 23, 0, 0, 0, 4, 103, 65, 77, - 65, 0, 0, -79, -113, 11, -4, 97, - 5, 0, 0, 0, 1, 115, 82, 71, - 66, 0, -82, -50, 28, -23, 0, 0, - 0, 6, 80, 76, 84, 69, -1, -1, - -1, 0, 0, 0, 85, -62, -45, 126, - 0, 0, 0, -115, 73, 68, 65, 84, - 56, -53, -19, -46, -79, 17, -128, 32, - 12, 5, -48, 120, 22, -106, -116, -32, - 40, -84, 101, -121, -93, 57, 10, 35, - 88, 82, 112, 126, 3, -60, 104, 6, - -112, 70, 127, -59, -69, -53, 29, 33, - -127, -24, 79, -49, -52, -15, 41, 36, - 34, -105, 85, 124, -14, 88, 27, 6, - 28, 68, 1, 82, 62, 22, -95, -108, - 55, -95, 40, -9, -110, -12, 98, -107, - 76, -41, -105, -62, -50, 111, -60, 46, - -14, -4, 24, -89, 42, -103, 16, 63, - -72, -11, -15, 48, -62, 102, -44, 102, - -73, -56, 56, -21, -128, 92, -70, -124, - 117, -46, -67, -77, 82, 80, 121, -44, - -56, 116, 93, -45, -90, -5, -29, -24, - -83, -75, 52, -34, 55, -22, 102, -21, - -105, -124, -23, 71, 87, -7, -25, -59, - -100, -73, -92, -122, -7, -109, -49, -80, - -89, 0, 0, 0, 0, 73, 69, 78, - 68, -82, 66, 96, -126 - }); - // proto.write(RestrictedImageProto.METADATA, flattened_protobuf); - proto.end(imageToken); + // The debug method takes two file descriptors. The first is for text + // output, which we will drop. The second is for binary data, which + // will be the protobuf data. + final IBiometricsFace daemon = getFaceDaemon(); + if (daemon != null) { + FileOutputStream devnull = null; + try { + devnull = new FileOutputStream("/dev/null"); + final NativeHandle handle = new NativeHandle( + new FileDescriptor[] { devnull.getFD(), fd }, + new int[0], false); + daemon.debug(handle, new ArrayList<String>(Arrays.asList(args))); + } catch (IOException | RemoteException ex) { + Slog.d(TAG, "error while reading face debugging data", ex); + } finally { + if (devnull != null) { + try { + devnull.close(); + } catch (IOException ex) { + } + } + } } - - // Face service metadata - // proto.write(RestrictedImageSetProto.METADATA, flattened_protobuf); - - proto.end(setToken); - proto.flush(); } } 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/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java index 9989c1a511ad..87fe785ca614 100644 --- a/services/core/java/com/android/server/incident/IncidentCompanionService.java +++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java @@ -55,7 +55,8 @@ public class IncidentCompanionService extends SystemService { * Dump argument for proxying restricted image dumps to the services * listed in the config. */ - private static String[] RESTRICTED_IMAGE_DUMP_ARGS = new String[] { "--restricted_image" }; + private static String[] RESTRICTED_IMAGE_DUMP_ARGS = new String[] { + "--hal", "--restricted_image" }; /** * The two permissions, for sendBroadcastAsUserMultiplePermissions. 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..fdb499b5cd0e 100644 --- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java @@ -140,6 +140,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { private AudioPlayerStateMonitor mAudioPlayerStateMonitor; // Used to notify System UI and Settings when remote volume was changed. + @GuardedBy("mLock") final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers = new RemoteCallbackList<>(); @@ -171,7 +172,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; } @@ -287,17 +288,19 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { if (!session.isActive()) { return; } - int size = mRemoteVolumeControllers.beginBroadcast(); - MediaSession.Token token = session.getSessionToken(); - for (int i = size - 1; i >= 0; i--) { - try { - IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); - cb.remoteVolumeChanged(token, flags); - } catch (Exception e) { - Log.w(TAG, "Error sending volume change.", e); + synchronized (mLock) { + int size = mRemoteVolumeControllers.beginBroadcast(); + MediaSession.Token token = session.getSessionToken(); + for (int i = size - 1; i >= 0; i--) { + try { + IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); + cb.remoteVolumeChanged(token, flags); + } catch (Exception e) { + Log.w(TAG, "Error sending volume change.", e); + } } + mRemoteVolumeControllers.finishBroadcast(); } - mRemoteVolumeControllers.finishBroadcast(); } @Override @@ -647,19 +650,21 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { return; } - int size = mRemoteVolumeControllers.beginBroadcast(); - MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); - MediaSession.Token token = record == null ? null : record.getSessionToken(); + synchronized (mLock) { + int size = mRemoteVolumeControllers.beginBroadcast(); + MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); + MediaSession.Token token = record == null ? null : record.getSessionToken(); - for (int i = size - 1; i >= 0; i--) { - try { - IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); - cb.updateRemoteController(token); - } catch (Exception e) { - Log.w(TAG, "Error sending default remote volume.", e); + for (int i = size - 1; i >= 0; i--) { + try { + IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i); + cb.updateRemoteController(token); + } catch (Exception e) { + Log.w(TAG, "Error sending default remote volume.", e); + } } + mRemoteVolumeControllers.finishBroadcast(); } - mRemoteVolumeControllers.finishBroadcast(); } void pushSession2TokensChangedLocked(int userId) { @@ -1037,8 +1042,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); } @@ -1675,11 +1681,13 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); - try { - enforceStatusBarServicePermission("listen for volume changes", pid, uid); - mRemoteVolumeControllers.register(rvc); - } finally { - Binder.restoreCallingIdentity(token); + synchronized (mLock) { + try { + enforceStatusBarServicePermission("listen for volume changes", pid, uid); + mRemoteVolumeControllers.register(rvc); + } finally { + Binder.restoreCallingIdentity(token); + } } } @@ -1688,11 +1696,13 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); - try { - enforceStatusBarServicePermission("listen for volume changes", pid, uid); - mRemoteVolumeControllers.unregister(rvc); - } finally { - Binder.restoreCallingIdentity(token); + synchronized (mLock) { + try { + enforceStatusBarServicePermission("listen for volume changes", pid, uid); + mRemoteVolumeControllers.unregister(rvc); + } finally { + Binder.restoreCallingIdentity(token); + } } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7f1b25ca3ca3..042ac8c5760e 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1689,6 +1689,9 @@ public class NotificationManagerService extends SystemService { mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray( com.android.internal.R.array.config_nonBlockableNotificationPackages)); + + mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( + com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); } @Override diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 7e74cc2368cd..1f5b99cb3349 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -80,6 +80,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -96,7 +97,7 @@ public class ZenModeHelper { private final Context mContext; private final H mHandler; private final SettingsObserver mSettingsObserver; - @VisibleForTesting protected final AppOpsManager mAppOps; + private final AppOpsManager mAppOps; @VisibleForTesting protected final NotificationManager mNotificationManager; @VisibleForTesting protected ZenModeConfig mDefaultConfig; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); @@ -123,11 +124,13 @@ public class ZenModeHelper { @VisibleForTesting protected boolean mIsBootComplete; + private String[] mPriorityOnlyDndExemptPackages; + public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) { mContext = context; mHandler = new H(looper); addCallback(mMetrics); - mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mAppOps = context.getSystemService(AppOpsManager.class); mNotificationManager = context.getSystemService(NotificationManager.class); mDefaultConfig = readDefaultConfig(mContext.getResources()); @@ -214,6 +217,10 @@ public class ZenModeHelper { loadConfigForUser(user, "onUserUnlocked"); } + void setPriorityOnlyDndExemptPackages(String[] packages) { + mPriorityOnlyDndExemptPackages = packages; + } + private void loadConfigForUser(int user, String reason) { if (mUser == user || user < UserHandle.USER_SYSTEM) return; mUser = user; @@ -994,53 +1001,47 @@ public class ZenModeHelper { for (int usage : AudioAttributes.SDK_USAGES) { final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage); if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) { - applyRestrictions(false /*mute*/, usage); + applyRestrictions(zenPriorityOnly, false /*mute*/, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) { - applyRestrictions(muteNotifications || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteNotifications || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) { - applyRestrictions(muteCalls || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteCalls || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) { - applyRestrictions(muteAlarms || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteAlarms || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) { - applyRestrictions(muteMedia || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteMedia || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) { if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { // normally DND will only restrict touch sounds, not haptic feedback/vibrations - applyRestrictions(muteSystem || muteEverything, usage, + applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage, AppOpsManager.OP_PLAY_AUDIO); - applyRestrictions(false, usage, AppOpsManager.OP_VIBRATE); + applyRestrictions(zenPriorityOnly, false, usage, AppOpsManager.OP_VIBRATE); } else { - applyRestrictions(muteSystem || muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage); } } else { - applyRestrictions(muteEverything, usage); + applyRestrictions(zenPriorityOnly, muteEverything, usage); } } } @VisibleForTesting - protected void applyRestrictions(boolean mute, int usage, int code) { - final String[] exceptionPackages = null; // none (for now) - - // Only do this if we are executing within the system process... otherwise - // we are running as test code, so don't have access to the protected call. - if (Process.myUid() == Process.SYSTEM_UID) { - final long ident = Binder.clearCallingIdentity(); - try { - mAppOps.setRestriction(code, usage, - mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, - exceptionPackages); - } finally { - Binder.restoreCallingIdentity(ident); - } + protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage, int code) { + final long ident = Binder.clearCallingIdentity(); + try { + mAppOps.setRestriction(code, usage, + mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, + zenPriorityOnly ? mPriorityOnlyDndExemptPackages : null); + } finally { + Binder.restoreCallingIdentity(ident); } } @VisibleForTesting - protected void applyRestrictions(boolean mute, int usage) { - applyRestrictions(mute, usage, AppOpsManager.OP_VIBRATE); - applyRestrictions(mute, usage, AppOpsManager.OP_PLAY_AUDIO); + protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage) { + applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_VIBRATE); + applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_PLAY_AUDIO); } 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/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 7f48970b445a..e6313d9dcbe4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -813,7 +813,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @Override public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, - IntentSender statusReceiver, int userId) throws RemoteException { + IntentSender statusReceiver, int userId) { final int callingUid = Binder.getCallingUid(); mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) { @@ -952,6 +952,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @Override public void onUserActionRequired(Intent intent) { + if (mTarget == null) { + return; + } final Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); fillIn.putExtra(PackageInstaller.EXTRA_STATUS, @@ -972,6 +975,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements SystemMessage.NOTE_PACKAGE_STATE, mNotification); } + if (mTarget == null) { + return; + } final Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); fillIn.putExtra(PackageInstaller.EXTRA_STATUS, diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index a935c652be53..74fb4b27100e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -841,6 +841,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) { + if (hasParentSessionId()) { + throw new IllegalStateException( + "Session " + sessionId + " is a child of multi-package session " + + mParentSessionId + " and may not be committed directly."); + } if (!markAsCommitted(statusReceiver, forTransfer)) { return; } @@ -2037,6 +2042,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void abandon() { + if (hasParentSessionId()) { + throw new IllegalStateException( + "Session " + sessionId + " is a child of multi-package session " + + mParentSessionId + " and may not be abandoned directly."); + } synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); @@ -2079,13 +2089,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override - public void addChildSessionId(int childSessionId) throws RemoteException { + public void addChildSessionId(int childSessionId) { final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId); - if (childSession == null) { - throw new RemoteException("Unable to add child.", - new PackageManagerException("Child session " + childSessionId - + " does not exist"), - false, true).rethrowAsRuntimeException(); + if (childSession == null + || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId) + || childSession.mCommitted + || childSession.mDestroyed) { + throw new IllegalStateException("Unable to add child session " + childSessionId + + " as it does not exist or is in an invalid state."); } synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); @@ -2124,11 +2135,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { if (parentSessionId != SessionInfo.INVALID_ID && mParentSessionId != SessionInfo.INVALID_ID) { - throw new RemoteException("Unable to set parent session.", - new PackageManagerException( - "The parent of " + sessionId + " is" + " already set to " - + mParentSessionId), false, - true).rethrowAsRuntimeException(); + throw new IllegalStateException("The parent of " + sessionId + " is" + " already" + + "set to " + mParentSessionId); } this.mParentSessionId = parentSessionId; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index d3aa746f7596..d7da06cc92bc 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; } } @@ -10213,7 +10225,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void destroyAppProfilesLIF(PackageParser.Package pkg, int userId) { + private void destroyAppProfilesLIF(PackageParser.Package pkg) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; @@ -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); } } @@ -14603,6 +14620,20 @@ public class PackageManagerService extends IPackageManager.Stub return mUser; } + /** + * Gets the user handle for the user that the rollback agent should + * use to look up information about this installation when enabling + * rollback. + */ + UserHandle getRollbackUser() { + // The session for packages installed for "all" users is + // associated with the "system" user. + if (mUser == UserHandle.ALL) { + return UserHandle.SYSTEM; + } + return mUser; + } + HandlerParams setTraceMethod(String traceMethod) { this.traceMethod = traceMethod; return this; @@ -15221,7 +15252,7 @@ public class PackageManagerService extends IPackageManager.Stub installedUsers); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, - getUser().getIdentifier()); + getRollbackUser().getIdentifier()); enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), PACKAGE_MIME_TYPE); enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -16696,6 +16727,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 +16767,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 +16824,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()) { @@ -18590,7 +18624,7 @@ public class PackageManagerService extends IPackageManager.Stub } destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); - destroyAppProfilesLIF(resolvedPkg, UserHandle.USER_ALL); + destroyAppProfilesLIF(resolvedPkg); if (outInfo != null) { outInfo.dataRemoved = true; } @@ -18599,10 +18633,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 +18667,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 +19180,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 +19209,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 +19220,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 +19235,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; } } @@ -19317,6 +19364,8 @@ public class PackageManagerService extends IPackageManager.Stub pkg = mPackages.get(ps.name); } + destroyAppProfilesLIF(pkg); + final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds() : new int[] {userId}; for (int nextUserId : userIds) { @@ -19325,15 +19374,20 @@ public class PackageManagerService extends IPackageManager.Stub + nextUserId); } - destroyAppDataLIF(pkg, userId, + destroyAppDataLIF(pkg, nextUserId, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); - destroyAppProfilesLIF(pkg, userId); - clearDefaultBrowserIfNeededForUser(ps.name, userId); + clearDefaultBrowserIfNeededForUser(ps.name, nextUserId); removeKeystoreDataIfNeeded(nextUserId, ps.appId); - synchronized (mPackages) { - if (clearPackagePreferredActivitiesLPw(ps.name, nextUserId)) { + 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 +19850,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); - } } } @@ -19864,26 +19919,28 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "replace preferred activity"); - synchronized (mPackages) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS) - != PackageManager.PERMISSION_GRANTED) { + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.SET_PREFERRED_APPLICATIONS) + != PackageManager.PERMISSION_GRANTED) { + synchronized (mPackages) { if (getUidTargetSdkVersionLockedLPr(callingUid) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring replacePreferredActivity() from uid " + Binder.getCallingUid()); return; } - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); + } - PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); + synchronized (mPackages) { + final PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); if (pir != null) { // Get all of the existing entries that exactly match this filter. - ArrayList<PreferredActivity> existing = pir.findFilters(filter); + final ArrayList<PreferredActivity> existing = pir.findFilters(filter); if (existing != null && existing.size() == 1) { - PreferredActivity cur = existing.get(0); + final PreferredActivity cur = existing.get(0); if (DEBUG_PREFERRED) { Slog.i(TAG, "Checking replace of preferred:"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); @@ -19913,14 +19970,13 @@ public class PackageManagerService extends IPackageManager.Stub return; } } - if (existing != null) { if (DEBUG_PREFERRED) { Slog.i(TAG, existing.size() + " existing preferred matches for:"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); } - for (int i = 0; i < existing.size(); i++) { - PreferredActivity pa = existing.get(i); + for (int i = existing.size() - 1; i >= 0; --i) { + final PreferredActivity pa = existing.get(i); if (DEBUG_PREFERRED) { Slog.i(TAG, "Removing existing preferred activity " + pa.mPref.mComponent + ":"); @@ -19930,9 +19986,9 @@ public class PackageManagerService extends IPackageManager.Stub } } } - addPreferredActivityInternal(filter, match, set, activity, true, userId, - "Replacing preferred"); } + addPreferredActivityInternal(filter, match, set, activity, true, userId, + "Replacing preferred"); } @Override @@ -19963,25 +20019,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 +20062,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 +20117,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 +20187,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 +20237,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 +20330,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 +20658,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 +20782,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() { @@ -23720,9 +23811,7 @@ public class PackageManagerService extends IPackageManager.Stub } return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0) | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0) - | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0) - | (appInfo.isProductServices() - ? IPackageManagerNative.LOCATION_PRODUCT_SERVICES : 0)); + | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0)); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 4e4a0e420d86..6b804df2e068 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2423,6 +2423,16 @@ class PackageManagerShellCommand extends ShellCommand { sessionParams.setStaged(); break; case "--enable-rollback": + if (params.installerPackageName == null) { + // com.android.shell has the TEST_MANAGE_ROLLBACKS + // permission needed to enable rollback for non-module + // packages, which is likely what the user wants when + // enabling rollback through the shell command. Set + // the installer to com.android.shell if no installer + // has been provided so that the user doesn't have to + // remember to set it themselves. + params.installerPackageName = "com.android.shell"; + } sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; break; default: 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 1908b3f8b366..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(); @@ -487,7 +487,7 @@ public class StagingManager { } try { apkParentSession.addChildSessionId(apkChildSession.sessionId); - } catch (RemoteException e) { + } catch (IllegalStateException e) { Slog.e(TAG, "Failed to add a child session for installing the APK files", e); return false; } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index c75a462d5bc1..dd63e3ca290e 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -18,12 +18,6 @@ package com.android.server.pm.permission; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; -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_NONE; -import static android.app.AppOpsManager.permissionToOp; -import static android.app.AppOpsManager.permissionToOpCode; import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; @@ -40,8 +34,6 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRAD import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL; import static android.content.pm.PackageManager.RESTRICTED_PERMISSIONS_ENABLED; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; -import static android.os.UserHandle.getAppId; -import static android.os.UserHandle.getUid; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; @@ -56,8 +48,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.AppOpsManager; -import android.app.AppOpsManagerInternal; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PermissionWhitelistFlags; @@ -1309,9 +1299,6 @@ public class PermissionManagerService { updatedUserIds); updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions, permissionsState, pkg, updatedUserIds); - - // TODO: Move to PermissionPolicyService - setAppOpsLocked(permissionsState, pkg); } // Persist the runtime permissions state for users with changes. If permissions @@ -1327,23 +1314,6 @@ public class PermissionManagerService { } /** - * Set app op for a app-op related to a permission. - * - * @param permission The permission the app-op belongs to - * @param pkg The package the permission belongs to - * @param userId The user to be changed - * @param mode The new mode to set - */ - private void setAppOpMode(@NonNull String permission, @NonNull PackageParser.Package pkg, - @UserIdInt int userId, int mode) { - AppOpsManagerInternal appOpsInternal = LocalServices.getService( - AppOpsManagerInternal.class); - - appOpsInternal.setUidMode(permissionToOpCode(permission), - getUid(userId, getAppId(pkg.applicationInfo.uid)), mode); - } - - /** * Revoke permissions that are not implicit anymore and that have * {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set. * @@ -1357,8 +1327,6 @@ public class PermissionManagerService { private @NonNull int[] revokePermissionsNoLongerImplicitLocked( @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, @NonNull int[] updatedUserIds) { - AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); - String pkgName = pkg.packageName; boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; @@ -1390,23 +1358,6 @@ public class PermissionManagerService { } flagsToRemove |= USER_PERMISSION_FLAGS; - - List<String> fgPerms = mBackgroundPermissions.get(permission); - if (fgPerms != null) { - int numFgPerms = fgPerms.size(); - for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) { - String fgPerm = fgPerms.get(fgPermNum); - - int mode = appOpsManager.unsafeCheckOpRaw( - permissionToOp(fgPerm), - getUid(userId, getAppId(pkg.applicationInfo.uid)), - pkgName); - - if (mode == MODE_ALLOWED) { - setAppOpMode(fgPerm, pkg, userId, MODE_FOREGROUND); - } - } - } } ps.updatePermissionFlags(bp, userId, flagsToRemove, 0); @@ -1438,91 +1389,39 @@ public class PermissionManagerService { @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm, @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, @UserIdInt int userId) { - AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class); String pkgName = pkg.packageName; + boolean isGranted = false; + int flags = 0; - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - if (permissionToOp(newPerm) != null) { - int mostLenientSourceMode = MODE_ERRORED; - int flags = 0; - - // Find most lenient source permission state. - int numSourcePerms = sourcePerms.size(); - for (int i = 0; i < numSourcePerms; i++) { - String sourcePerm = sourcePerms.valueAt(i); - - if (ps.hasRuntimePermission(sourcePerm, userId)) { - int sourceOp = permissionToOpCode(sourcePerm); - - if (sourceOp != OP_NONE) { - int mode = appOpsManager.checkOperationUnchecked(sourceOp, - getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName); - - if (mode == MODE_FOREGROUND || mode == MODE_ERRORED) { - Log.wtf(TAG, "split permission" + sourcePerm + " has app-op state " - + AppOpsManager.MODE_NAMES[mode]); - - continue; - } - - // Leniency order: allowed < ignored < default - if (mode < mostLenientSourceMode) { - mostLenientSourceMode = mode; - flags = ps.getPermissionFlags(sourcePerm, userId); - } else if (mode == mostLenientSourceMode) { - flags |= ps.getPermissionFlags(sourcePerm, userId); - } - } - } + int numSourcePerm = sourcePerms.size(); + for (int i = 0; i < numSourcePerm; i++) { + String sourcePerm = sourcePerms.valueAt(i); + if ((ps.hasRuntimePermission(sourcePerm, userId)) + || ps.hasInstallPermission(sourcePerm)) { + if (!isGranted) { + flags = 0; } - if (mostLenientSourceMode != MODE_ERRORED) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, newPerm + " inherits app-ops state " + mostLenientSourceMode - + " from " + sourcePerms + " for " + pkgName); - } - - setAppOpMode(newPerm, pkg, userId, mostLenientSourceMode); - - // Add permission flags - ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, - flags); - } - } - } else { - boolean isGranted = false; - int flags = 0; - - int numSourcePerm = sourcePerms.size(); - for (int i = 0; i < numSourcePerm; i++) { - String sourcePerm = sourcePerms.valueAt(i); - if ((ps.hasRuntimePermission(sourcePerm, userId)) - || ps.hasInstallPermission(sourcePerm)) { - if (!isGranted) { - flags = 0; - } - - isGranted = true; + isGranted = true; + flags |= ps.getPermissionFlags(sourcePerm, userId); + } else { + if (!isGranted) { flags |= ps.getPermissionFlags(sourcePerm, userId); - } else { - if (!isGranted) { - flags |= ps.getPermissionFlags(sourcePerm, userId); - } } } + } - if (isGranted) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms - + " for " + pkgName); - } - - ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId); + if (isGranted) { + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms + + " for " + pkgName); } - // Add permission flags - ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags); + ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId); } + + // Add permission flags + ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags); } /** @@ -1632,48 +1531,6 @@ public class PermissionManagerService { return updatedUserIds; } - /** - * Fix app-op modes for runtime permissions. - * - * @param permsState The state of the permissions of the package - * @param pkg The package information - */ - private void setAppOpsLocked(@NonNull PermissionsState permsState, - @NonNull PackageParser.Package pkg) { - for (int userId : UserManagerService.getInstance().getUserIds()) { - int numPerms = pkg.requestedPermissions.size(); - for (int i = 0; i < numPerms; i++) { - String permission = pkg.requestedPermissions.get(i); - - // For pre-M apps the runtime permission do not store the state - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - continue; - } - - PermissionState state = permsState.getRuntimePermissionState(permission, userId); - if (state == null) { - continue; - } - - // Adjust app-op mods for foreground/background permissions. If an package used to - // have both fg and bg permission granted and it lost the bg permission during an - // upgrade the app-op mode should get downgraded to foreground. - if (state.isGranted()) { - BasePermission bp = mSettings.getPermission(permission); - - if (bp != null && bp.perm != null && bp.perm.info != null - && bp.perm.info.backgroundPermission != null) { - PermissionState bgState = permsState.getRuntimePermissionState( - bp.perm.info.backgroundPermission, userId); - - setAppOpMode(permission, pkg, userId, bgState != null && bgState.isGranted() - ? MODE_ALLOWED : MODE_FOREGROUND); - } - } - } - } - } - private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { boolean allowed = false; final int NP = PackageParser.NEW_PERMISSIONS.length; diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 67f30dc2e9fc..1fd8b711d348 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -17,8 +17,10 @@ package com.android.server.policy; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; +import static android.content.pm.PackageManager.GET_PERMISSIONS; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.content.Context; @@ -29,6 +31,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; +import android.os.Build; import android.os.Process; import android.os.UserHandle; import android.permission.PermissionControllerManager; @@ -158,37 +161,59 @@ public final class PermissionPolicyService extends SystemService { }); } + private static @Nullable Context getUserContext(@NonNull Context context, + @NonNull UserHandle user) { + if (context.getUser().equals(user)) { + return context; + } else { + try { + return context.createPackageContextAsUser(context.getPackageName(), 0, user); + } catch (NameNotFoundException e) { + Slog.e(LOG_TAG, "Cannot create context for user " + user, e); + return null; + } + } + } + + /** + * Synchronize a single package. + */ private static void synchronizePackagePermissionsAndAppOpsForUser(@NonNull Context context, @NonNull String packageName, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); - final PackageParser.Package pkg = packageManagerInternal.getPackage(packageName); + final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0, + Process.SYSTEM_UID, userId); if (pkg == null) { return; } - final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(context); - synchroniser.addPackage(context, pkg, userId); + final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser( + getUserContext(context, UserHandle.of(userId))); + synchroniser.addPackage(pkg.packageName); final String[] sharedPkgNames = packageManagerInternal.getPackagesForSharedUserId( - pkg.mSharedUserId, userId); + pkg.sharedUserId, userId); if (sharedPkgNames != null) { for (String sharedPkgName : sharedPkgNames) { final PackageParser.Package sharedPkg = packageManagerInternal .getPackage(sharedPkgName); if (sharedPkg != null) { - synchroniser.addPackage(context, sharedPkg, userId); + synchroniser.addPackage(sharedPkg.packageName); } } } synchroniser.syncPackages(); } + /** + * Synchronize all packages + */ private static void synchronizePermissionsAndAppOpsForUser(@NonNull Context context, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); - final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(context); - packageManagerInternal.forEachPackage((pkg) -> - synchronizer.addPackage(context, pkg, userId)); + final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser( + getUserContext(context, UserHandle.of(userId))); + packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName)); synchronizer.syncPackages(); } @@ -198,17 +223,47 @@ public final class PermissionPolicyService extends SystemService { */ private static class PermissionToOpSynchroniser { private final @NonNull Context mContext; - - private final @NonNull SparseIntArray mUids = new SparseIntArray(); - private final @NonNull SparseArray<String> mPackageNames = new SparseArray<>(); - private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray(); - private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray(); + private final @NonNull PackageManager mPackageManager; + private final @NonNull AppOpsManager mAppOpsManager; + + /** All uid that need to be synchronized */ + private final @NonNull SparseIntArray mAllUids = new SparseIntArray(); + + /** + * All ops that need to be restricted + * + * @see #syncRestrictedOps + */ + private final @NonNull ArrayList<OpToRestrict> mOpsToRestrict = new ArrayList<>(); + + /** + * All ops that need to be unrestricted + * + * @see #syncRestrictedOps + */ + private final @NonNull ArrayList<OpToUnrestrict> mOpsToUnrestrict = new ArrayList<>(); + + /** + * All foreground permissions + * + * @see #syncOpsOfFgPermissions() + */ + private final @NonNull ArrayList<FgPermission> mFgPermOps = new ArrayList<>(); PermissionToOpSynchroniser(@NonNull Context context) { mContext = context; + mPackageManager = context.getPackageManager(); + mAppOpsManager = context.getSystemService(AppOpsManager.class); } - void syncPackages() { + /** + * Set app ops that belong to restricted permissions. + * + * <p>This processes ops previously added by {@link #addOpIfRestricted} + */ + private void syncRestrictedOps() { + final SparseIntArray unprocessedUids = mAllUids.clone(); + // TRICKY: we set the app op for a restricted permission to allow if the app // requesting the permission is whitelisted and to deny if the app requesting // the permission is not whitelisted. However, there is another case where an @@ -222,52 +277,48 @@ public final class PermissionPolicyService extends SystemService { final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid = new SparseArray<>(); - final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); - final int allowedCount = mAllowedUidOps.size(); - for (int i = 0; i < allowedCount; i++) { - final int opCode = mAllowedUidOps.keyAt(i); - final int uid = mAllowedUidOps.valueAt(i); - final String packageName = mPackageNames.valueAt(i); - setUidModeAllowed(appOpsManager, opCode, uid, packageName); + final int unrestrictCount = mOpsToUnrestrict.size(); + for (int i = 0; i < unrestrictCount; i++) { + final OpToUnrestrict op = mOpsToUnrestrict.get(i); + setUidModeAllowed(op.code, op.uid, op.packageName); // Keep track this permission was requested by the UID. List<String> unrequestedRestrictedPermissions = - unrequestedRestrictedPermissionsForUid.get(uid); + unrequestedRestrictedPermissionsForUid.get(op.uid); if (unrequestedRestrictedPermissions == null) { unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); - unrequestedRestrictedPermissionsForUid.put(uid, + unrequestedRestrictedPermissionsForUid.put(op.uid, unrequestedRestrictedPermissions); } - unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode)); + unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); - mUids.delete(uid); + unprocessedUids.delete(op.uid); } - final int defaultCount = mDefaultUidOps.size(); - for (int i = 0; i < defaultCount; i++) { - final int opCode = mDefaultUidOps.keyAt(i); - final int uid = mDefaultUidOps.valueAt(i); - setUidModeDefault(appOpsManager, opCode, uid); + final int restrictCount = mOpsToRestrict.size(); + for (int i = 0; i < restrictCount; i++) { + final OpToRestrict op = mOpsToRestrict.get(i); + setUidModeDefault(op.code, op.uid); // Keep track this permission was requested by the UID. List<String> unrequestedRestrictedPermissions = - unrequestedRestrictedPermissionsForUid.get(uid); + unrequestedRestrictedPermissionsForUid.get(op.uid); if (unrequestedRestrictedPermissions == null) { unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); - unrequestedRestrictedPermissionsForUid.put(uid, + unrequestedRestrictedPermissionsForUid.put(op.uid, unrequestedRestrictedPermissions); } - unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode)); + unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); - mUids.delete(uid); + unprocessedUids.delete(op.uid); } // Give root access - mUids.put(Process.ROOT_UID, Process.ROOT_UID); + unprocessedUids.put(Process.ROOT_UID, Process.ROOT_UID); // Add records for UIDs that don't use any restricted permissions. - final int uidCount = mUids.size(); + final int uidCount = unprocessedUids.size(); for (int i = 0; i < uidCount; i++) { - final int uid = mUids.keyAt(i); + final int uid = unprocessedUids.keyAt(i); unrequestedRestrictedPermissionsForUid.put(uid, new ArrayList<>(sAllRestrictedPermissions)); } @@ -280,7 +331,7 @@ public final class PermissionPolicyService extends SystemService { if (unrequestedRestrictedPermissions != null) { final int uid = unrequestedRestrictedPermissionsForUid.keyAt(i); final String[] packageNames = (uid != Process.ROOT_UID) - ? mContext.getPackageManager().getPackagesForUid(uid) + ? mPackageManager.getPackagesForUid(uid) : new String[] {"root"}; if (packageNames == null) { continue; @@ -289,8 +340,7 @@ public final class PermissionPolicyService extends SystemService { for (int j = 0; j < permissionCount; j++) { final String permission = unrequestedRestrictedPermissions.get(j); for (String packageName : packageNames) { - setUidModeAllowed(appOpsManager, - AppOpsManager.permissionToOpCode(permission), uid, + setUidModeAllowed(AppOpsManager.permissionToOpCode(permission), uid, packageName); } } @@ -298,19 +348,115 @@ public final class PermissionPolicyService extends SystemService { } } - private void addPackage(@NonNull Context context, - @NonNull PackageParser.Package pkg, @UserIdInt int userId) { - final PackageManager packageManager = context.getPackageManager(); + /** + * Set app ops that belong to restricted permissions. + * + * <p>This processed ops previously added by {@link #addOpIfRestricted} + */ + private void syncOpsOfFgPermissions() { + int numFgPermOps = mFgPermOps.size(); + for (int i = 0; i < numFgPermOps; i++) { + FgPermission perm = mFgPermOps.get(i); + + if (mPackageManager.checkPermission(perm.fgPermissionName, perm.packageName) + == PackageManager.PERMISSION_GRANTED) { + if (mPackageManager.checkPermission(perm.bgPermissionName, perm.packageName) + == PackageManager.PERMISSION_GRANTED) { + mAppOpsManager.setUidMode( + AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid, + AppOpsManager.MODE_ALLOWED); + } else { + mAppOpsManager.setUidMode( + AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid, + AppOpsManager.MODE_FOREGROUND); + } + } else { + mAppOpsManager.setUidMode( + AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid, + AppOpsManager.MODE_IGNORED); + } + } + } + + /** + * Synchronize all previously {@link #addPackage added} packages. + */ + void syncPackages() { + syncRestrictedOps(); + syncOpsOfFgPermissions(); + } + + /** + * Add op that belong to a restricted permission for later processing in + * {@link #syncRestrictedOps}. + * + * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. + * + * @param permissionInfo The permission that is currently looked at + * @param pkg The package looked at + */ + private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo, + @NonNull PackageInfo pkg) { + final String permission = permissionInfo.name; + final int opCode = AppOpsManager.permissionToOpCode(permission); + final int uid = pkg.applicationInfo.uid; + + if (!permissionInfo.isRestricted()) { + return; + } + + final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED + && (mPackageManager.getPermissionFlags(permission, pkg.packageName, + mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + + if (permissionInfo.isHardRestricted()) { + if (applyRestriction) { + mOpsToRestrict.add(new OpToRestrict(uid, opCode)); + } else { + mOpsToUnrestrict.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); + } + } else if (permissionInfo.isSoftRestricted()) { + //TODO: Implement soft restrictions like storage here. + } + } + + private void addOpIfFgPermissions(@NonNull PermissionInfo permissionInfo, + @NonNull PackageInfo pkg) { + if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + // Pre-M apps do not store their fg/bg state in the permissions + return; + } + + if (permissionInfo.backgroundPermission == null) { + return; + } - final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid)); - final UserHandle userHandle = UserHandle.of(userId); + mFgPermOps.add(new FgPermission(pkg.applicationInfo.uid, pkg.packageName, + permissionInfo.name, permissionInfo.backgroundPermission)); + } + + /** + * Add a package for {@link #syncPackages() processing} later. + * + * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. + * + * @param pkgName The package to add for later processing. + */ + void addPackage(@NonNull String pkgName) { + final PackageInfo pkg; + try { + pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); + } catch (NameNotFoundException e) { + return; + } - mUids.put(uid, uid); + mAllUids.put(pkg.applicationInfo.uid, pkg.applicationInfo.uid); - final int permissionCount = pkg.requestedPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - final String permission = pkg.requestedPermissions.get(i); + if (pkg.requestedPermissions == null) { + return; + } + for (String permission : pkg.requestedPermissions) { final int opCode = AppOpsManager.permissionToOpCode(permission); if (opCode == AppOpsManager.OP_NONE) { continue; @@ -318,44 +464,63 @@ public final class PermissionPolicyService extends SystemService { final PermissionInfo permissionInfo; try { - permissionInfo = packageManager.getPermissionInfo(permission, 0); + permissionInfo = mPackageManager.getPermissionInfo(permission, 0); } catch (PackageManager.NameNotFoundException e) { continue; } - if (!permissionInfo.isRestricted()) { - continue; - } - - final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED - && (packageManager.getPermissionFlags(permission, pkg.packageName, - userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; - - if (permissionInfo.isHardRestricted()) { - if (applyRestriction) { - mDefaultUidOps.put(opCode, uid); - } else { - mPackageNames.put(opCode, pkg.packageName); - mAllowedUidOps.put(opCode, uid); - } - } else if (permissionInfo.isSoftRestricted()) { - //TODO: Implement soft restrictions like storage here. - } + addOpIfRestricted(permissionInfo, pkg); + addOpIfFgPermissions(permissionInfo, pkg); } } - private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager, - int opCode, int uid, @NonNull String packageName) { - final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager + private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { + final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { - appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); + mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); } } - private static void setUidModeDefault(@NonNull AppOpsManager appOpsManager, - int opCode, int uid) { - appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); + private void setUidModeDefault(int opCode, int uid) { + mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); + } + + private class OpToRestrict { + final int uid; + final int code; + + OpToRestrict(int uid, int code) { + this.uid = uid; + this.code = code; + } + } + + private class OpToUnrestrict { + final int uid; + final @NonNull String packageName; + final int code; + + OpToUnrestrict(int uid, @NonNull String packageName, int code) { + this.uid = uid; + this.packageName = packageName; + this.code = code; + } + } + + private class FgPermission { + final int uid; + final @NonNull String packageName; + final @NonNull String fgPermissionName; + final @NonNull String bgPermissionName; + + private FgPermission(int uid, @NonNull String packageName, + @NonNull String fgPermissionName, @NonNull String bgPermissionName) { + this.uid = uid; + this.packageName = packageName; + this.fgPermissionName = fgPermissionName; + this.bgPermissionName = bgPermissionName; + } } } } 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/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index 03814453fc52..1552fd517d30 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -312,10 +312,8 @@ public class ThermalManagerService extends SystemService { if (!mThermalEventListeners.register(listener, null)) { return false; } - if (mHalReady.get()) { - // Notify its callback after new client registered. - postEventListenerCurrentTemperatures(listener, null); - } + // Notify its callback after new client registered. + postEventListenerCurrentTemperatures(listener, null); return true; } finally { Binder.restoreCallingIdentity(token); @@ -334,10 +332,8 @@ public class ThermalManagerService extends SystemService { if (!mThermalEventListeners.register(listener, new Integer(type))) { return false; } - if (mHalReady.get()) { - // Notify its callback after new client registered. - postEventListenerCurrentTemperatures(listener, new Integer(type)); - } + // Notify its callback after new client registered. + postEventListenerCurrentTemperatures(listener, new Integer(type)); return true; } finally { Binder.restoreCallingIdentity(token); @@ -398,10 +394,8 @@ public class ThermalManagerService extends SystemService { if (!mThermalStatusListeners.register(listener)) { return false; } - if (mHalReady.get()) { - // Notify its callback after new client registered. - postStatusListener(listener); - } + // Notify its callback after new client registered. + postStatusListener(listener); return true; } finally { Binder.restoreCallingIdentity(token); diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index b2ac1b884483..654c47780f4a 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -147,6 +147,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C mLegacyRoleResolver = legacyRoleResolver; + RoleControllerManager.initializeRemoteServiceComponentName(context); + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); @@ -231,7 +233,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C // Run grants again Slog.i(LOG_TAG, "Granting default permissions..."); CompletableFuture<Void> result = new CompletableFuture<>(); - getOrCreateControllerService(userId).grantDefaultRoles(FgThread.getExecutor(), + getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(), successful -> { if (successful) { userState.setPackagesHash(packagesHash); @@ -318,7 +320,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } @NonNull - private RoleControllerManager getOrCreateControllerService(@UserIdInt int userId) { + private RoleControllerManager getOrCreateController(@UserIdInt int userId) { synchronized (mLock) { RoleControllerManager controller = mControllers.get(userId); if (controller == null) { @@ -330,7 +332,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } catch (NameNotFoundException e) { throw new RuntimeException(e); } - controller = new RoleControllerManager(context, FgThread.getHandler()); + controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName( + FgThread.getHandler(), context); mControllers.put(userId, controller); } return controller; @@ -474,7 +477,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); Preconditions.checkNotNull(callback, "callback cannot be null"); - getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, flags, + getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags, callback); } @@ -494,7 +497,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); Preconditions.checkNotNull(callback, "callback cannot be null"); - getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, flags, + getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags, callback); } @@ -513,7 +516,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); Preconditions.checkNotNull(callback, "callback cannot be null"); - getOrCreateControllerService(userId).onClearRoleHolders(roleName, flags, callback); + getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback); } @Override @@ -738,10 +741,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } }); if (packageName != null) { - getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, + getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, packageName, 0, callback); } else { - getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, + getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, callback); } try { @@ -762,10 +765,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } }); if (packageName != null) { - getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, + getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER, packageName, 0, callback); } else { - getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, + getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0, callback); } } @@ -791,10 +794,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C callback.accept(successful); }); if (packageName != null) { - getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME, + getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_HOME, packageName, 0, remoteCallback); } else { - getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0, + getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0, remoteCallback); } } 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/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java index e967a92f1891..78f1e69d4649 100644 --- a/services/core/java/com/android/server/wm/AppTaskImpl.java +++ b/services/core/java/com/android/server/wm/AppTaskImpl.java @@ -106,6 +106,10 @@ class AppTaskImpl extends IAppTask.Stub { final long origId = Binder.clearCallingIdentity(); try { synchronized (mService.mGlobalLock) { + if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, + "Move to front")) { + return; + } WindowProcessController callerApp = null; if (appThread != null) { callerApp = mService.getProcessController(appThread); diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index c1d872f23f0f..b5e706710823 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -435,6 +435,18 @@ public class BoundsAnimationController { moveFromFullscreen, moveToFullscreen, animationType); } + /** + * Cancel existing animation if the destination was modified. + */ + void cancel(final BoundsAnimationTarget target) { + final BoundsAnimator existing = mRunningAnimations.get(target); + if (existing != null) { + // Cancel animation. Since its already started, send animation end to client. + if (DEBUG) Slog.d(TAG, "cancel: mTarget= " + target); + existing.cancelAndCallAnimationEnd(); + } + } + @VisibleForTesting BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to, int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState, 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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 0f4e123923b0..ee4e33e4cfaa 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -250,8 +250,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // on the IME target. We mainly have this container grouping so we can keep track of all the IME // window containers together and move them in-sync if/when needed. We use a subclass of // WindowContainer which is omitted from screen magnification, as the IME is never magnified. - private final NonMagnifiableWindowContainers mImeWindowsContainers = - new NonMagnifiableWindowContainers("mImeWindowsContainers", mWmService); + private final NonAppWindowContainers mImeWindowsContainers = + new NonAppWindowContainers("mImeWindowsContainers", mWmService); private WindowState mTmpWindow; private WindowState mTmpWindow2; @@ -4642,16 +4642,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } - private class NonMagnifiableWindowContainers extends NonAppWindowContainers { - NonMagnifiableWindowContainers(String name, WindowManagerService service) { - super(name, service); - } - - @Override - void applyMagnificationSpec(Transaction t, MagnificationSpec spec) { - } - }; - SurfaceControl.Builder makeSurface(SurfaceSession s) { return mWmService.makeSurfaceBuilder(s) .setParent(mWindowingLayer); 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/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index f31416cdc620..432ca3387ce7 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -292,9 +292,9 @@ class TaskSnapshotController { } final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE; return new TaskSnapshot(appWindowToken.mActivityComponent, buffer, - appWindowToken.getConfiguration().orientation, getInsets(mainWindow), - isLowRamDevice /* reduced */, scaleFraction /* scale */, true /* isRealSnapshot */, - task.getWindowingMode(), getSystemUiVisibility(task), + screenshotBuffer.getColorSpace(), appWindowToken.getConfiguration().orientation, + getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */, + true /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task), !appWindowToken.fillsParent() || isWindowTranslucent); } @@ -383,10 +383,10 @@ class TaskSnapshotController { // Note, the app theme snapshot is never translucent because we enforce a non-translucent // color above return new TaskSnapshot(topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(), - topChild.getConfiguration().orientation, mainWindow.getStableInsets(), - ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */, - false /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task), - false); + hwBitmap.getColorSpace(), topChild.getConfiguration().orientation, + mainWindow.getStableInsets(), ActivityManager.isLowRamDeviceStatic() /* reduced */, + 1.0f /* scale */, false /* isRealSnapshot */, task.getWindowingMode(), + getSystemUiVisibility(task), false); } /** diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java index d30843b9c589..f7b8945d9729 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java @@ -89,7 +89,8 @@ class TaskSnapshotLoader { } ComponentName topActivityComponent = ComponentName.unflattenFromString( proto.topActivityComponent); - return new TaskSnapshot(topActivityComponent, buffer, proto.orientation, + return new TaskSnapshot(topActivityComponent, buffer, bitmap.getColorSpace(), + proto.orientation, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), reducedResolution, reducedResolution ? mPersister.getReducedScale() : 1f, proto.isRealSnapshot, proto.windowingMode, proto.systemUiVisibility, diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index bdb4d0474865..7515b3fa1249 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -388,7 +388,9 @@ public class TaskStack extends WindowContainer<Task> implements * @return true if bounds were updated to some non-empty value. */ boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) { + boolean animating = false; if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) { + animating = true; getFinalAnimationBounds(mTmpRect2); } else { mTmpRect2.set(inOutBounds); @@ -398,6 +400,13 @@ public class TaskStack extends WindowContainer<Task> implements if (updated) { inOutBounds.set(mTmpRect3); + // The final boundary is updated while there is an existing boundary animation. Let's + // cancel this animation to prevent the obsolete animation overwritten updated bounds. + if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) { + final DisplayContent displayContent = getDisplayContent(); + displayContent.mBoundsAnimationController.getHandler().post(() -> + displayContent.mBoundsAnimationController.cancel(this)); + } // Once we've set the bounds based on the rotation of the old bounds in the new // orientation, clear the animation target bounds since they are obsolete, and // cancel any currently running animations @@ -1585,7 +1594,6 @@ public class TaskStack extends WindowContainer<Task> implements mBoundsAnimatingRequested = false; mBoundsAnimating = true; - mCancelCurrentBoundsAnimation = false; mAnimationType = animationType; // If we are changing UI mode, as in the PiP to fullscreen @@ -1645,7 +1653,7 @@ public class TaskStack extends WindowContainer<Task> implements mBoundsAnimationTarget, false /* forceUpdate */); } - if (finalStackSize != null) { + if (finalStackSize != null && !mCancelCurrentBoundsAnimation) { setPinnedStackSize(finalStackSize, null); } else { // We have been canceled, so the final stack size is null, still run the @@ -1758,6 +1766,7 @@ public class TaskStack extends WindowContainer<Task> implements } final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType; + mCancelCurrentBoundsAnimation = false; displayContent.mBoundsAnimationController.getHandler().post(() -> { displayContent.mBoundsAnimationController.animateBounds(this, fromBounds, finalToBounds, animationDuration, finalSchedulePipModeChangedState, diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ce496f47be54..8ed2a15b2b98 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2107,7 +2107,7 @@ public class WindowManagerService extends IWindowManager.Stub if (shouldRelayout) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1"); - result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility); + result = win.relayoutVisibleWindow(result, attrChanges); try { result = createSurfaceControl(outSurfaceControl, result, win, winAnimator); 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 08ade37c995c..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(); } @@ -4446,7 +4446,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets); } - int relayoutVisibleWindow(int result, int attrChanges, int oldVisibility) { + int relayoutVisibleWindow(int result, int attrChanges) { final boolean wasVisible = isVisibleLw(); result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0; @@ -4466,7 +4466,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mDestroying = false; mWmService.mDestroySurface.remove(this); } - if (oldVisibility == View.GONE) { + if (!wasVisible) { mWinAnimator.mEnterAnimationPending = true; } diff --git a/services/core/jni/com_android_server_TestNetworkService.cpp b/services/core/jni/com_android_server_TestNetworkService.cpp index b90ff233c1ac..36a6fde36191 100644 --- a/services/core/jni/com_android_server_TestNetworkService.cpp +++ b/services/core/jni/com_android_server_TestNetworkService.cpp @@ -54,12 +54,12 @@ static void throwException(JNIEnv* env, int error, const char* action, const cha jniThrowException(env, "java/lang/IllegalStateException", msg.c_str()); } -static int createTunInterface(JNIEnv* env, const char* iface) { +static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) { base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK)); ifreq ifr{}; // Allocate interface. - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI; strlcpy(ifr.ifr_name, iface, IFNAMSIZ); if (ioctl(tun.get(), TUNSETIFF, &ifr)) { throwException(env, errno, "allocating", ifr.ifr_name); @@ -80,23 +80,23 @@ static int createTunInterface(JNIEnv* env, const char* iface) { //------------------------------------------------------------------------------ -static jint create(JNIEnv* env, jobject /* thiz */, jstring jIface) { +static jint create(JNIEnv* env, jobject /* thiz */, jboolean isTun, jstring jIface) { ScopedUtfChars iface(env, jIface); if (!iface.c_str()) { jniThrowNullPointerException(env, "iface"); return -1; } - int tun = createTunInterface(env, iface.c_str()); + int tun = createTunTapInterface(env, isTun, iface.c_str()); - // Any exceptions will be thrown from the createTunInterface call + // Any exceptions will be thrown from the createTunTapInterface call return tun; } //------------------------------------------------------------------------------ static const JNINativeMethod gMethods[] = { - {"jniCreateTun", "(Ljava/lang/String;)I", (void*)create}, + {"jniCreateTunTap", "(ZLjava/lang/String;)I", (void*)create}, }; int register_android_server_TestNetworkService(JNIEnv* env) { 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/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java index c8d1eb413ecf..74fe81c6f68e 100644 --- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java @@ -30,6 +30,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -38,6 +39,7 @@ import static org.testng.Assert.expectThrows; import android.app.backup.BackupManager; import android.app.backup.IBackupObserver; import android.app.backup.ISelectBackupTransportCallback; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; @@ -48,6 +50,7 @@ import android.os.Binder; import android.os.HandlerThread; import android.os.PowerManager; import android.os.PowerSaveState; +import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.provider.Settings; @@ -66,6 +69,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @@ -1130,6 +1134,31 @@ public class UserBackupManagerServiceTest { /* transportManager */ null)); } + /** + * Test verifying that creating a new instance registers the broadcast receiver for package + * tracking + */ + @Test + public void testCreateAndInitializeService_registersPackageTrackingReceiver() throws Exception { + Context contextSpy = Mockito.spy(mContext); + + UserBackupManagerService service = UserBackupManagerService.createAndInitializeService( + USER_ID, + contextSpy, + new Trampoline(mContext), + mBackupThread, + mBaseStateDir, + mDataDir, + mTransportManager); + + BroadcastReceiver packageTrackingReceiver = service.getPackageTrackingReceiver(); + assertThat(packageTrackingReceiver).isNotNull(); + + // One call for package changes and one call for sd card events. + verify(contextSpy, times(2)).registerReceiverAsUser( + eq(packageTrackingReceiver), eq(UserHandle.of(USER_ID)), any(), any(), any()); + } + private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() { return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks( USER_ID, mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager); diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index 164570a84cb0..cc64323e51c7 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -86,6 +86,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.net.Uri; import android.os.ConditionVariable; import android.os.DeadObjectException; @@ -100,6 +101,7 @@ import android.util.Pair; import com.android.internal.backup.IBackupTransport; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.KeyValueBackupJob; @@ -116,7 +118,6 @@ import com.android.server.backup.testing.TransportTestUtils; import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.testing.shadows.FrameworkShadowLooper; import com.android.server.testing.shadows.ShadowApplicationPackageManager; -import com.android.server.testing.shadows.ShadowBackupActivityThread; import com.android.server.testing.shadows.ShadowBackupDataInput; import com.android.server.testing.shadows.ShadowBackupDataOutput; import com.android.server.testing.shadows.ShadowEventLog; @@ -163,8 +164,7 @@ import java.util.stream.Stream; ShadowBackupDataInput.class, ShadowBackupDataOutput.class, ShadowEventLog.class, - ShadowQueuedWork.class, - ShadowBackupActivityThread.class, + ShadowQueuedWork.class }) @Presubmit public class KeyValueBackupTaskTest { @@ -179,6 +179,7 @@ public class KeyValueBackupTaskTest { @Mock private IBackupObserver mObserver; @Mock private IBackupManagerMonitor mMonitor; @Mock private OnTaskFinishedListener mListener; + @Mock private PackageManagerInternal mPackageManagerInternal; private UserBackupManagerService mBackupManagerService; private TransportData mTransport; private ShadowLooper mShadowBackupLooper; @@ -243,6 +244,11 @@ public class KeyValueBackupTaskTest { mShadowBackupLooper = shadowOf(mBackupHandler.getLooper()); ShadowEventLog.setUp(); mReporter = spy(new KeyValueBackupReporter(mBackupManagerService, mObserver, mMonitor)); + + when(mPackageManagerInternal.getApplicationEnabledState(any(), anyInt())) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + LocalServices.removeServiceForTest(PackageManagerInternal.class); + LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); } @After @@ -471,7 +477,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgentWithData(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1); runTask(task); @@ -484,7 +490,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgentWithData(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE); @@ -498,7 +504,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgentWithData(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1); runTask(task); @@ -1307,7 +1313,7 @@ public class KeyValueBackupTaskTest { argThat(packageInfo(PM_PACKAGE)), any(), anyInt())) .then(copyBackupDataTo(backupDataPath)); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> { @@ -1371,7 +1377,7 @@ public class KeyValueBackupTaskTest { setUpAgent(PACKAGE_1); when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> { @@ -1395,7 +1401,7 @@ public class KeyValueBackupTaskTest { setUpAgent(PACKAGE_1); when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> { @@ -1957,7 +1963,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); + doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); runTask(task); @@ -1970,7 +1976,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); + doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); runTask(task); @@ -1983,7 +1989,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); + doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); runTask(task); @@ -1996,7 +2002,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel)); @@ -2011,7 +2017,7 @@ public class KeyValueBackupTaskTest { TransportMock transportMock = setUpInitializedTransport(mTransport); setUpAgent(PACKAGE_1); BackupAgent pmAgent = spy(createPmAgent()); - when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); + doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent(); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); agentOnBackupDo( pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel)); diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java deleted file mode 100644 index ca2e3b6dafef..000000000000 --- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java +++ /dev/null @@ -1,79 +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.server.testing.shadows; - -import android.app.ActivityThread; -import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.RemoteException; - -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowActivityThread; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -import javax.annotation.Nonnull; - -/** - * Extends the existing {@link ShadowActivityThread} to add support for - * {@link PackageManager#getApplicationEnabledSetting(String)} in the shadow {@link PackageManager} - * returned by {@link ShadowBackupActivityThread#getPackageManager()}. - */ -@Implements(value = ActivityThread.class, isInAndroidSdk = false, looseSignatures = true) -public class ShadowBackupActivityThread extends ShadowActivityThread { - @Implementation - public static Object getPackageManager() { - ClassLoader classLoader = ShadowActivityThread.class.getClassLoader(); - Class<?> iPackageManagerClass; - try { - iPackageManagerClass = classLoader.loadClass("android.content.pm.IPackageManager"); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - - return Proxy.newProxyInstance( - classLoader, - new Class[] {iPackageManagerClass}, - new InvocationHandler() { - @Override - public Object invoke(Object proxy, @Nonnull Method method, Object[] args) - throws Exception { - if (method.getName().equals("getApplicationInfo")) { - String packageName = (String) args[0]; - int flags = (Integer) args[1]; - - try { - return RuntimeEnvironment.application - .getPackageManager() - .getApplicationInfo(packageName, flags); - } catch (PackageManager.NameNotFoundException e) { - throw new RemoteException(e.getMessage()); - } - } else if (method.getName().equals("getApplicationEnabledSetting")) { - return 0; - } else { - return null; - } - } - }); - } -} 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/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java deleted file mode 100644 index 97a6e6657b7a..000000000000 --- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java +++ /dev/null @@ -1,1217 +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.server.backup.testutils; - -import android.content.ComponentName; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.IntentSender; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.ChangedPackages; -import android.content.pm.IDexModuleRegisterCallback; -import android.content.pm.IOnPermissionsChangeListener; -import android.content.pm.IPackageDataObserver; -import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageDeleteObserver2; -import android.content.pm.IPackageInstaller; -import android.content.pm.IPackageManager; -import android.content.pm.IPackageMoveObserver; -import android.content.pm.IPackageStatsObserver; -import android.content.pm.InstrumentationInfo; -import android.content.pm.KeySet; -import android.content.pm.ModuleInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ParceledListSlice; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; -import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.content.pm.SuspendDialogInfo; -import android.content.pm.VerifierDeviceIdentity; -import android.content.pm.VersionedPackage; -import android.content.pm.dex.IArtManager; -import android.graphics.Bitmap; -import android.os.IBinder; -import android.os.PersistableBundle; -import android.os.RemoteException; - -import java.util.List; - -/** - * Stub for IPackageManager to use in tests. - */ -public class IPackageManagerStub implements IPackageManager { - public static PackageInfo sPackageInfo; - public static int sApplicationEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - - @Override - public PackageInfo getPackageInfo(String packageName, int flags, int userId) - throws RemoteException { - return sPackageInfo; - } - - @Override - public int getApplicationEnabledSetting(String packageName, int userId) throws RemoteException { - return sApplicationEnabledSetting; - } - - @Override - public void checkPackageStartable(String packageName, int userId) throws RemoteException { - - } - - @Override - public boolean isPackageAvailable(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public int getPackageUid(String packageName, int flags, int userId) throws RemoteException { - return 0; - } - - @Override - public int[] getPackageGids(String packageName, int flags, int userId) throws RemoteException { - return new int[0]; - } - - @Override - public String[] currentToCanonicalPackageNames(String[] names) throws RemoteException { - return new String[0]; - } - - @Override - public String[] canonicalToCurrentPackageNames(String[] names) throws RemoteException { - return new String[0]; - } - - @Override - public PermissionInfo getPermissionInfo(String name, String packageName, int flags) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryPermissionsByGroup(String group, int flags) - throws RemoteException { - return null; - } - - @Override - public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getAllPermissionGroups(int flags) throws RemoteException { - return null; - } - - @Override - public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ActivityInfo getActivityInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean activitySupportsIntent(ComponentName className, Intent intent, - String resolvedType) - throws RemoteException { - return false; - } - - @Override - public ActivityInfo getReceiverInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ServiceInfo getServiceInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ProviderInfo getProviderInfo(ComponentName className, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public int checkPermission(String permName, String pkgName, int userId) throws RemoteException { - return 0; - } - - @Override - public int checkUidPermission(String permName, int uid) throws RemoteException { - return 0; - } - - @Override - public boolean addPermission(PermissionInfo info) throws RemoteException { - return false; - } - - @Override - public void removePermission(String name) throws RemoteException { - - } - - @Override - public void grantRuntimePermission(String packageName, String permissionName, int userId) - throws RemoteException { - - } - - @Override - public void revokeRuntimePermission(String packageName, String permissionName, int userId) - throws RemoteException { - - } - - @Override - public void resetRuntimePermissions() throws RemoteException { - - } - - @Override - public int getPermissionFlags(String permissionName, String packageName, int userId) - throws RemoteException { - return 0; - } - - @Override - public void updatePermissionFlags(String permissionName, String packageName, int flagMask, - int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) - throws RemoteException { - - } - - @Override - public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) - throws RemoteException { - - } - - @Override - public List<String> getWhitelistedRestrictedPermissions(String packageName, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public boolean addWhitelistedRestrictedPermission(String packageName, String permission, - int whitelistFlags, int userId) throws RemoteException { - return false; - } - - @Override - public boolean removeWhitelistedRestrictedPermission(String packageName, String permission, - int whitelistFlags, int userId) throws RemoteException { - return false; - } - - @Override - public boolean shouldShowRequestPermissionRationale(String permissionName, String packageName, - int userId) throws RemoteException { - return false; - } - - @Override - public boolean isProtectedBroadcast(String actionName) throws RemoteException { - return false; - } - - @Override - public int checkSignatures(String pkg1, String pkg2) throws RemoteException { - return 0; - } - - @Override - public int checkUidSignatures(int uid1, int uid2) throws RemoteException { - return 0; - } - - @Override - public List<String> getAllPackages() throws RemoteException { - return null; - } - - @Override - public String[] getPackagesForUid(int uid) throws RemoteException { - return new String[0]; - } - - @Override - public String getNameForUid(int uid) throws RemoteException { - return null; - } - - @Override - public String[] getNamesForUids(int[] uids) throws RemoteException { - return new String[0]; - } - - @Override - public int getUidForSharedUser(String sharedUserName) throws RemoteException { - return 0; - } - - @Override - public int getFlagsForUid(int uid) throws RemoteException { - return 0; - } - - @Override - public int getPrivateFlagsForUid(int uid) throws RemoteException { - return 0; - } - - @Override - public boolean isUidPrivileged(int uid) throws RemoteException { - return false; - } - - @Override - public String[] getAppOpPermissionPackages(String permissionName) throws RemoteException { - return new String[0]; - } - - @Override - public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId, - int targetUserId) throws RemoteException { - return false; - } - - @Override - public ParceledListSlice queryIntentActivities(Intent intent, String resolvedType, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentActivityOptions(ComponentName caller, Intent[] specifics, - String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentReceivers(Intent intent, String resolvedType, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentServices(Intent intent, String resolvedType, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryIntentContentProviders(Intent intent, String resolvedType, - int flags, int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getInstalledPackages(int flags, int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getPackagesHoldingPermissions(String[] permissions, int flags, - int userId) throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getInstalledApplications(int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getPersistentApplications(int flags) throws RemoteException { - return null; - } - - @Override - public ProviderInfo resolveContentProvider(String name, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) - throws RemoteException { - - } - - @Override - public ParceledListSlice queryContentProviders(String processName, int uid, int flags, - String metaDataKey) throws RemoteException { - return null; - } - - @Override - public InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice queryInstrumentation(String targetPackage, int flags) - throws RemoteException { - return null; - } - - @Override - public void finishPackageInstall(int token, boolean didLaunch) throws RemoteException { - - } - - @Override - public void setInstallerPackageName(String targetPackage, String installerPackageName) - throws RemoteException { - - } - - @Override - public void setApplicationCategoryHint(String packageName, int categoryHint, - String callerPackageName) throws RemoteException { - - } - - @Override - public void deletePackageAsUser(String packageName, int versionCode, - IPackageDeleteObserver observer, int userId, int flags) throws RemoteException { - - } - - @Override - public void deletePackageVersioned(VersionedPackage versionedPackage, - IPackageDeleteObserver2 observer, int userId, int flags) throws RemoteException { - - } - - @Override - public String getInstallerPackageName(String packageName) throws RemoteException { - return null; - } - - @Override - public void resetApplicationPreferences(int userId) throws RemoteException { - - } - - @Override - public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) - throws RemoteException { - return null; - } - - @Override - public void setLastChosenActivity(Intent intent, String resolvedType, int flags, - IntentFilter filter, int match, ComponentName activity) throws RemoteException { - - } - - @Override - public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, - ComponentName activity, int userId) throws RemoteException { - - } - - @Override - public void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set, - ComponentName activity, int userId) throws RemoteException { - - } - - @Override - public void clearPackagePreferredActivities(String packageName) throws RemoteException { - - } - - @Override - public int getPreferredActivities(List<IntentFilter> outFilters, - List<ComponentName> outActivities, String packageName) throws RemoteException { - return 0; - } - - @Override - public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity, - int userId) throws RemoteException { - - } - - @Override - public void clearPackagePersistentPreferredActivities(String packageName, int userId) - throws RemoteException { - - } - - @Override - public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage, - int sourceUserId, int targetUserId, int flags) throws RemoteException { - - } - - @Override - public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage) - throws RemoteException { - - } - - @Override - public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames, - int restrictionFlags, int userId) throws RemoteException { - return new String[0]; - } - - @Override - public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended, - PersistableBundle appExtras, PersistableBundle launcherExtras, SuspendDialogInfo dialogInfo, - String callingPackage, int userId) throws RemoteException { - return new String[0]; - } - - @Override - public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) - throws RemoteException { - return new String[0]; - } - - @Override - public boolean isPackageSuspendedForUser(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId) - throws RemoteException { - return null; - } - - @Override - public byte[] getPreferredActivityBackup(int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public void restorePreferredActivities(byte[] backup, int userId) throws RemoteException { - - } - - @Override - public byte[] getDefaultAppsBackup(int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public void restoreDefaultApps(byte[] backup, int userId) throws RemoteException { - - } - - @Override - public byte[] getIntentFilterVerificationBackup(int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public void restoreIntentFilterVerification(byte[] backup, int userId) throws RemoteException { - - } - - @Override - public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates) - throws RemoteException { - return null; - } - - @Override - public void setHomeActivity(ComponentName className, int userId) throws RemoteException { - - } - - @Override - public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, - int userId) throws RemoteException { - - } - - @Override - public int getComponentEnabledSetting(ComponentName componentName, int userId) - throws RemoteException { - return 0; - } - - @Override - public void setApplicationEnabledSetting(String packageName, int newState, int flags, - int userId, - String callingPackage) throws RemoteException { - - } - - @Override - public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, - String apkFile, - int pid) throws RemoteException { - - } - - @Override - public void flushPackageRestrictionsAsUser(int userId) throws RemoteException { - - } - - @Override - public void setPackageStoppedState(String packageName, boolean stopped, int userId) - throws RemoteException { - - } - - @Override - public void freeStorageAndNotify(String volumeUuid, long freeStorageSize, int storageFlags, - IPackageDataObserver observer) throws RemoteException { - - } - - @Override - public void freeStorage(String volumeUuid, long freeStorageSize, int storageFlags, - IntentSender pi) throws RemoteException { - - } - - @Override - public void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer) - throws RemoteException { - - } - - @Override - public void deleteApplicationCacheFilesAsUser(String packageName, int userId, - IPackageDataObserver observer) throws RemoteException { - - } - - @Override - public void clearApplicationUserData(String packageName, IPackageDataObserver observer, - int userId) throws RemoteException { - - } - - @Override - public void clearApplicationProfileData(String packageName) throws RemoteException { - - } - - @Override - public void getPackageSizeInfo(String packageName, int userHandle, - IPackageStatsObserver observer) - throws RemoteException { - - } - - @Override - public String[] getSystemSharedLibraryNames() throws RemoteException { - return new String[0]; - } - - @Override - public ParceledListSlice getSystemAvailableFeatures() throws RemoteException { - return null; - } - - @Override - public boolean hasSystemFeature(String name, int version) throws RemoteException { - return false; - } - - @Override - public void enterSafeMode() throws RemoteException { - - } - - @Override - public boolean isSafeMode() throws RemoteException { - return false; - } - - @Override - public void systemReady() throws RemoteException { - - } - - @Override - public boolean hasSystemUidErrors() throws RemoteException { - return false; - } - - @Override - public void performFstrimIfNeeded() throws RemoteException { - - } - - @Override - public void updatePackagesIfNeeded() throws RemoteException { - - } - - @Override - public void notifyPackageUse(String packageName, int reason) throws RemoteException { - - } - - @Override - public void notifyDexLoad(String loadingPackageName, List<String> classLoadersNames, - List<String> classPaths, String loaderIsa) throws RemoteException { - - } - - @Override - public void registerDexModule(String packageName, String dexModulePath, boolean isSharedModule, - IDexModuleRegisterCallback callback) throws RemoteException { - - } - - @Override - public boolean performDexOptMode(String packageName, boolean checkProfiles, - String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) - throws RemoteException { - return false; - } - - @Override - public boolean performDexOptSecondary(String packageName, String targetCompilerFilter, - boolean force) throws RemoteException { - return false; - } - - @Override - public boolean compileLayouts(String packageName) throws RemoteException { - return false; - } - - @Override - public void dumpProfiles(String packageName) throws RemoteException { - - } - - @Override - public void forceDexOpt(String packageName) throws RemoteException { - - } - - @Override - public boolean runBackgroundDexoptJob(List<String> packageNames) throws RemoteException { - return false; - } - - @Override - public void reconcileSecondaryDexFiles(String packageName) throws RemoteException { - - } - - @Override - public int getMoveStatus(int moveId) throws RemoteException { - return 0; - } - - @Override - public void registerMoveCallback(IPackageMoveObserver callback) throws RemoteException { - - } - - @Override - public void unregisterMoveCallback(IPackageMoveObserver callback) throws RemoteException { - - } - - @Override - public int movePackage(String packageName, String volumeUuid) throws RemoteException { - return 0; - } - - @Override - public int movePrimaryStorage(String volumeUuid) throws RemoteException { - return 0; - } - - @Override - public boolean addPermissionAsync(PermissionInfo info) throws RemoteException { - return false; - } - - @Override - public boolean setInstallLocation(int loc) throws RemoteException { - return false; - } - - @Override - public int getInstallLocation() throws RemoteException { - return 0; - } - - @Override - public int installExistingPackageAsUser(String packageName, int userId, int installFlags, - int installReason) throws RemoteException { - return 0; - } - - @Override - public void verifyPendingInstall(int id, int verificationCode) throws RemoteException { - - } - - @Override - public void extendVerificationTimeout(int id, int verificationCodeAtTimeout, - long millisecondsToDelay) throws RemoteException { - - } - - @Override - public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) - throws RemoteException { - - } - - @Override - public int getIntentVerificationStatus(String packageName, int userId) throws RemoteException { - return 0; - } - - @Override - public boolean updateIntentVerificationStatus(String packageName, int status, int userId) - throws RemoteException { - return false; - } - - @Override - public ParceledListSlice getIntentFilterVerifications(String packageName) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getAllIntentFilters(String packageName) throws RemoteException { - return null; - } - - @Override - public boolean setDefaultBrowserPackageName(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public String getDefaultBrowserPackageName(int userId) throws RemoteException { - return null; - } - - @Override - public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException { - return null; - } - - @Override - public boolean isFirstBoot() throws RemoteException { - return false; - } - - @Override - public boolean isOnlyCoreApps() throws RemoteException { - return false; - } - - @Override - public boolean isDeviceUpgrading() throws RemoteException { - return false; - } - - @Override - public void setPermissionEnforced(String permission, boolean enforced) throws RemoteException { - - } - - @Override - public boolean isPermissionEnforced(String permission) throws RemoteException { - return false; - } - - @Override - public boolean isStorageLow() throws RemoteException { - return false; - } - - @Override - public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId) - throws RemoteException { - return false; - } - - @Override - public boolean getApplicationHiddenSettingAsUser(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) - throws RemoteException { - - } - - @Override - public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) - throws RemoteException { - return false; - } - - @Override - public IPackageInstaller getPackageInstaller() throws RemoteException { - return null; - } - - @Override - public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId) - throws RemoteException { - return false; - } - - @Override - public boolean getBlockUninstallForUser(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public KeySet getKeySetByAlias(String packageName, String alias) throws RemoteException { - return null; - } - - @Override - public KeySet getSigningKeySet(String packageName) throws RemoteException { - return null; - } - - @Override - public boolean isPackageSignedByKeySet(String packageName, KeySet ks) throws RemoteException { - return false; - } - - @Override - public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks) - throws RemoteException { - return false; - } - - @Override - public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) - throws RemoteException { - - } - - @Override - public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) - throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) - throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) - throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToEnabledTelephonyDataServices(String[] packageNames, - int userId) throws RemoteException { - - } - - @Override - public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(String[] packageNames, - int userId) throws RemoteException { - - } - - @Override - public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) - throws RemoteException { - - } - - @Override - public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) - throws RemoteException { - - } - - @Override - public boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public String getPermissionControllerPackageName() throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getInstantApps(int userId) throws RemoteException { - return null; - } - - @Override - public byte[] getInstantAppCookie(String packageName, int userId) throws RemoteException { - return new byte[0]; - } - - @Override - public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) - throws RemoteException { - return false; - } - - @Override - public Bitmap getInstantAppIcon(String packageName, int userId) throws RemoteException { - return null; - } - - @Override - public boolean isInstantApp(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) - throws RemoteException { - return false; - } - - @Override - public void setUpdateAvailable(String packageName, boolean updateAvaialble) - throws RemoteException { - - } - - @Override - public String getServicesSystemSharedLibraryPackageName() throws RemoteException { - return null; - } - - @Override - public String getSharedSystemSharedLibraryPackageName() throws RemoteException { - return null; - } - - @Override - public ChangedPackages getChangedPackages(int sequenceNumber, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean isPackageDeviceAdminOnAnyUser(String packageName) throws RemoteException { - return false; - } - - @Override - public int getInstallReason(String packageName, int userId) throws RemoteException { - return 0; - } - - @Override - public ParceledListSlice getSharedLibraries(String packageName, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public ParceledListSlice getDeclaredSharedLibraries(String packageName, int flags, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean canRequestPackageInstalls(String packageName, int userId) - throws RemoteException { - return false; - } - - @Override - public void deletePreloadsFileCache() throws RemoteException { - - } - - @Override - public ComponentName getInstantAppResolverComponent() throws RemoteException { - return null; - } - - @Override - public ComponentName getInstantAppResolverSettingsComponent() throws RemoteException { - return null; - } - - @Override - public ComponentName getInstantAppInstallerComponent() throws RemoteException { - return null; - } - - @Override - public String getInstantAppAndroidId(String packageName, int userId) throws RemoteException { - return null; - } - - @Override - public IArtManager getArtManager() throws RemoteException { - return null; - } - - @Override - public void setHarmfulAppWarning(String packageName, CharSequence warning, int userId) - throws RemoteException { - - } - - @Override - public CharSequence getHarmfulAppWarning(String packageName, int userId) - throws RemoteException { - return null; - } - - @Override - public boolean hasSigningCertificate(String packageName, byte[] signingCertificate, int flags) - throws RemoteException { - return false; - } - - @Override - public boolean hasUidSigningCertificate(int uid, byte[] signingCertificate, int flags) - throws RemoteException { - return false; - } - - @Override - public String getSystemTextClassifierPackageName() throws RemoteException { - return null; - } - - @Override - public String getWellbeingPackageName() throws RemoteException { - return null; - } - - @Override - public String getSystemCaptionsServicePackageName() throws RemoteException { - return null; - } - - @Override - public String getAttentionServicePackageName() throws RemoteException { - return null; - } - - public String getIncidentReportApproverPackageName() throws RemoteException { - return null; - } - - @Override - public String getAppPredictionServicePackageName() { - return null; - } - - @Override - public boolean isPackageStateProtected(String packageName, int userId) throws RemoteException { - return false; - } - - @Override - public void sendDeviceCustomizationReadyBroadcast() throws RemoteException { - - } - - @Override - public List<ModuleInfo> getInstalledModules(int flags) throws RemoteException { - return null; - } - - @Override - public ModuleInfo getModuleInfo(String packageName, int flags) throws RemoteException { - return null; - } - - @Override - public int getRuntimePermissionsVersion(int userId) throws RemoteException { - return 0; - } - - @Override - public void setRuntimePermissionsVersion(int version, int userId) throws RemoteException { - - } - - @Override - public IBinder asBinder() { - return null; - } -} diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java index a92b576e5d0f..a9011756240d 100644 --- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -36,7 +37,6 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.backup.UserBackupManagerService; -import com.android.server.backup.testutils.IPackageManagerStub; import org.junit.Before; import org.junit.Test; @@ -54,14 +54,12 @@ public class AppBackupUtilsTest { private static final Signature SIGNATURE_3 = generateSignature((byte) 3); private static final Signature SIGNATURE_4 = generateSignature((byte) 4); - private IPackageManagerStub mPackageManagerStub; private PackageManagerInternal mMockPackageManagerInternal; private int mUserId; @Before public void setUp() throws Exception { - mPackageManagerStub = new IPackageManagerStub(); mMockPackageManagerInternal = mock(PackageManagerInternal.class); mUserId = UserHandle.USER_SYSTEM; @@ -76,7 +74,7 @@ public class AppBackupUtilsTest { applicationInfo.packageName = TEST_PACKAGE_NAME; boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -91,7 +89,7 @@ public class AppBackupUtilsTest { applicationInfo.packageName = TEST_PACKAGE_NAME; boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -105,7 +103,7 @@ public class AppBackupUtilsTest { applicationInfo.packageName = UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -118,12 +116,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.SYSTEM_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isTrue(); } @@ -136,12 +133,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = null; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isTrue(); } @@ -154,12 +150,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isTrue(); } @@ -172,12 +167,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.SYSTEM_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -190,12 +184,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = null; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -208,12 +201,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; - - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo, - mPackageManagerStub, mUserId); + mMockPackageManagerInternal, mUserId); assertThat(isEligible).isFalse(); } @@ -226,12 +218,11 @@ public class AppBackupUtilsTest { applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; applicationInfo.enabled = true; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isFalse(); } @@ -244,12 +235,12 @@ public class AppBackupUtilsTest { applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; applicationInfo.enabled = false; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } @@ -261,12 +252,12 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_ENABLED; - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isFalse(); } @@ -278,12 +269,12 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED; - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } @@ -295,12 +286,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; - - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } @@ -312,12 +302,11 @@ public class AppBackupUtilsTest { applicationInfo.uid = Process.FIRST_APPLICATION_UID; applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME; applicationInfo.packageName = TEST_PACKAGE_NAME; + when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId)) + .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); - IPackageManagerStub.sApplicationEnabledSetting = - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; - - boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub, - mUserId); + boolean isDisabled = + AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId); assertThat(isDisabled).isTrue(); } 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/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 355ff63d18f7..2d101dd87a0f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -349,6 +349,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner); when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG}); when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG}); + mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); // write to a test file; the system file isn't readable from tests mFile = new File(mContext.getCacheDir(), "test.xml"); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index 91d3e5e4d7f6..7e3d4b47bbdf 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -206,6 +206,7 @@ public class RoleObserverTest extends UiServiceTestCase { LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class)); + mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); mUsers = new ArrayList<>(); mUsers.add(new UserInfo(0, "system", 0)); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 08d83333e91b..89364500fd80 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -110,6 +110,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { private ZenModeHelper mZenModeHelperSpy; private Context mContext; private ContentResolver mContentResolver; + @Mock AppOpsManager mAppOps; @Before public void setUp() { @@ -127,6 +128,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { e.toString()); } + when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps); when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager); mConditionProviders = new ConditionProviders(mContext, new UserProfiles(), AppGlobals.getPackageManager()); @@ -219,10 +221,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyInt()); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + doNothing().when(mZenModeHelperSpy).applyRestrictions(eq(false), anyBoolean(), anyInt()); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_MEDIA); } @@ -233,9 +235,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, AudioAttributes.USAGE_MEDIA); } @@ -244,13 +246,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, AudioAttributes.USAGE_ALARM); // Media is a catch-all that includes games - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, AudioAttributes.USAGE_GAME); } @@ -262,17 +264,17 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.applyRestrictions(); // Total silence will silence alarms, media and system noises (but not vibrations) - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_ALARM); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_GAME); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_VIBRATE); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_UNKNOWN); } @@ -283,19 +285,19 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.applyRestrictions(); // Alarms only mode will not silence alarms - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ALARM); // Alarms only mode will not silence media - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_MEDIA); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_GAME); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_UNKNOWN); // Alarms only will silence system noises (but not vibrations) - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); } @@ -306,9 +308,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.applyRestrictions(); // Alarms only mode will silence calls despite priority-mode config - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_NOTIFICATION_RINGTONE); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); } @@ -319,7 +321,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false, AudioAttributes.USAGE_ALARM); } @@ -334,19 +336,64 @@ public class ZenModeHelperTest extends UiServiceTestCase { for (int usage : AudioAttributes.SDK_USAGES) { if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { // only mute audio, not vibrations - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, usage, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, usage, AppOpsManager.OP_PLAY_AUDIO); - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, usage, + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, usage, AppOpsManager.OP_VIBRATE); } else { boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage) != AudioAttributes.SUPPRESSIBLE_NEVER; - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, shouldMute, usage); } } } @Test + public void testApplyRestrictions_whitelist_priorityOnlyMode() { + mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); + mZenModeHelperSpy.applyRestrictions(); + + for (int usage : AudioAttributes.SDK_USAGES) { + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(new String[]{PKG_O})); + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(new String[]{PKG_O})); + } + } + + @Test + public void testApplyRestrictions_whitelist_alarmsOnlyMode() { + mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_ALARMS; + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); + mZenModeHelperSpy.applyRestrictions(); + + for (int usage : AudioAttributes.SDK_USAGES) { + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null)); + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null)); + } + } + + @Test + public void testApplyRestrictions_whitelist_totalSilenceMode() { + mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_NO_INTERRUPTIONS; + mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0); + mZenModeHelperSpy.applyRestrictions(); + + for (int usage : AudioAttributes.SDK_USAGES) { + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null)); + verify(mAppOps).setRestriction( + eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null)); + } + } + + @Test public void testZenUpgradeNotification() { // shows zen upgrade notification if stored settings says to shows, // zen has not been updated, boot is completed 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/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index d29e3fa6f546..c3b0a67e2ee1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -27,6 +27,7 @@ import android.app.ActivityManager.TaskSnapshot; import android.content.ComponentName; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -127,8 +128,9 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { Canvas c = buffer.lockCanvas(); c.drawColor(Color.RED); buffer.unlockCanvasAndPost(c); - return new TaskSnapshot(new ComponentName("", ""), buffer, ORIENTATION_PORTRAIT, - TEST_INSETS, mScale < 1f /* reducedResolution */, mScale, mIsRealSnapshot, + return new TaskSnapshot(new ComponentName("", ""), buffer, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, TEST_INSETS, + mScale < 1f /* reducedResolution */, mScale, mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index cb6dc6d42bd5..4ca01eca238b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -35,6 +35,7 @@ import android.app.ActivityManager.TaskSnapshot; import android.content.ComponentName; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -64,8 +65,9 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888, GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER); final TaskSnapshot snapshot = new TaskSnapshot(new ComponentName("", ""), buffer, - ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */, - WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */); + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, contentInsets, false, + 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, + 0 /* systemUiVisibility */, false /* isTranslucent */); mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test", createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT); 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/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index 80fb58d45078..12b20efcb0b3 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -344,10 +344,22 @@ public final class TelephonyPermissions { return true; } // if the calling package is null then return now as there's no way to perform the - // DevicePolicyManager device / profile owner checks. + // DevicePolicyManager device / profile owner and AppOp checks if (callingPackage == null) { return false; } + // Allow access to an app that has been granted the READ_DEVICE_IDENTIFIERS app op. + long token = Binder.clearCallingIdentity(); + AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService( + Context.APP_OPS_SERVICE); + try { + if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid, + callingPackage) == AppOpsManager.MODE_ALLOWED) { + return true; + } + } finally { + Binder.restoreCallingIdentity(token); + } // Allow access to a device / profile owner app. DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService( Context.DEVICE_POLICY_SERVICE); diff --git a/tests/FlickerTests/lib/Android.bp b/tests/FlickerTests/lib/Android.bp index 982fcbadddf7..5d8ed2c205e9 100644 --- a/tests/FlickerTests/lib/Android.bp +++ b/tests/FlickerTests/lib/Android.bp @@ -20,7 +20,7 @@ java_test { srcs: ["src/**/*.java"], static_libs: [ "androidx.test.janktesthelper", - "cts-amwm-util", + "cts-wm-util", "platformprotosnano", "layersprotosnano", "truth-prebuilt", 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", diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 98324850f3f5..3da22b4fb9fa 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -129,12 +129,20 @@ class ValueBodyPrinter : public ConstValueVisitor { constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS; if (attr->type_mask & kMask) { for (const auto& symbol : attr->symbols) { - printer_->Print(symbol.symbol.name.value().entry); - if (symbol.symbol.id) { - printer_->Print("("); + if (symbol.symbol.name) { + printer_->Print(symbol.symbol.name.value().entry); + + if (symbol.symbol.id) { + printer_->Print("("); + printer_->Print(symbol.symbol.id.value().to_string()); + printer_->Print(")"); + } + } else if (symbol.symbol.id) { printer_->Print(symbol.symbol.id.value().to_string()); - printer_->Print(")"); + } else { + printer_->Print("???"); } + printer_->Println(StringPrintf("=0x%08x", symbol.value)); } } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 62ea9af49f51..9010f3c9943e 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -75,7 +75,7 @@ interface IWifiManager boolean removePasspointConfiguration(in String fqdn, String packageName); - List<PasspointConfiguration> getPasspointConfigurations(); + List<PasspointConfiguration> getPasspointConfigurations(in String packageName); List<WifiConfiguration> getWifiConfigsForPasspointProfiles(in List<String> fqdnList); diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 950c6f801461..9d4b837ce2d1 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -967,6 +967,10 @@ public class WifiEnterpriseConfig implements Parcelable { * from the top-level domain and all the labels in domain_suffix_match shall be included in the * certificate. The certificate may include additional sub-level labels in addition to the * required labels. + * <p>More than one match string can be provided by using semicolons to separate the strings + * (e.g., example.org;example.com). When multiple strings are specified, a match with any one of + * the values is considered a sufficient match for the certificate, i.e., the conditions are + * ORed ogether. * <p>For example, domain_suffix_match=example.com would match test.example.com but would not * match test-example.com. * @param domain The domain value diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 140e9c324dfa..4115663b8bb8 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1778,7 +1778,7 @@ public class WifiManager { }) public List<PasspointConfiguration> getPasspointConfigurations() { try { - return mService.getPasspointConfigurations(); + return mService.getPasspointConfigurations(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index 842d78ddcda2..fcf8bd5eaa3e 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -124,7 +124,7 @@ public class BaseWifiService extends IWifiManager.Stub { } @Override - public List<PasspointConfiguration> getPasspointConfigurations() { + public List<PasspointConfiguration> getPasspointConfigurations(String packageName) { throw new UnsupportedOperationException(); } diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java index 01a4c53d618b..41f109a63759 100644 --- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java @@ -16,8 +16,11 @@ package android.net.wifi.p2p; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import android.os.Parcel; + import androidx.test.filters.SmallTest; import org.junit.Test; @@ -27,6 +30,8 @@ import org.junit.Test; */ @SmallTest public class WifiP2pConfigTest { + + private static final String DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff"; /** * Check network name setter */ @@ -113,4 +118,43 @@ public class WifiP2pConfigTest { // expected exception. } } + + @Test + /* + * Verify WifiP2pConfig basic operations + */ + public void testWifiP2pConfig() throws Exception { + WifiP2pConfig config = new WifiP2pConfig(); + config.deviceAddress = DEVICE_ADDRESS; + + WifiP2pConfig copiedConfig = new WifiP2pConfig(config); + // no equals operator, use toString for comparison. + assertEquals(config.toString(), copiedConfig.toString()); + + Parcel parcelW = Parcel.obtain(); + config.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiP2pConfig configFromParcel = WifiP2pConfig.CREATOR.createFromParcel(parcelR); + + // no equals operator, use toString for comparison. + assertEquals(config.toString(), configFromParcel.toString()); + + } + + @Test + /* + * Verify WifiP2pConfig invalidate API + */ + public void testInvalidate() throws Exception { + WifiP2pConfig config = new WifiP2pConfig(); + config.deviceAddress = DEVICE_ADDRESS; + config.invalidate(); + assertEquals("", config.deviceAddress); + } + } diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceListTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceListTest.java new file mode 100644 index 000000000000..22936bd352fe --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceListTest.java @@ -0,0 +1,75 @@ +/* + * 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.net.wifi.p2p; + +import static org.junit.Assert.assertEquals; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit test harness for {@link android.net.wifi.p2p.WifiP2pDeviceList} + */ +@SmallTest +public class WifiP2pDeviceListTest { + + private static final WifiP2pDevice TEST_DEVICE_1 = new WifiP2pDevice("aa:bb:cc:dd:ee:ff"); + private static final WifiP2pDevice TEST_DEVICE_2 = new WifiP2pDevice("aa:bb:cc:dd:ee:f1"); + private static final WifiP2pDevice TEST_DEVICE_3 = new WifiP2pDevice("11:22:33:44:55:66"); + private static final WifiP2pDevice TEST_DEVICE_4 = new WifiP2pDevice("a0:b0:c0:d0:e0:f0"); + + /** + * Verify basic operations. + */ + @Test + public void testListOperations() throws Exception { + WifiP2pDeviceList list = new WifiP2pDeviceList(); + list.update(TEST_DEVICE_1); + list.update(TEST_DEVICE_2); + list.update(TEST_DEVICE_3); + assertEquals(3, list.getDeviceList().size()); + + assertEquals(TEST_DEVICE_1, list.get(TEST_DEVICE_1.deviceAddress)); + assertEquals(null, list.get(TEST_DEVICE_4.deviceAddress)); + + list.remove(TEST_DEVICE_2.deviceAddress); + assertEquals(null, list.get(TEST_DEVICE_2.deviceAddress)); + + list.remove(TEST_DEVICE_3); + assertEquals(null, list.get(TEST_DEVICE_3.deviceAddress)); + + assertEquals(1, list.getDeviceList().size()); + + list.clear(); + assertEquals(0, list.getDeviceList().size()); + + Parcel parcelW = Parcel.obtain(); + list.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiP2pDeviceList fromParcel = WifiP2pDeviceList.CREATOR.createFromParcel(parcelR); + + assertEquals(list.toString(), fromParcel.toString()); + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pGroupListTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pGroupListTest.java new file mode 100644 index 000000000000..2402f5bb4658 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pGroupListTest.java @@ -0,0 +1,115 @@ +/* + * 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.net.wifi.p2p; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +/** + * Unit test harness for {@link android.net.wifi.p2p.WifiP2pGroupList} + */ +@SmallTest +public class WifiP2pGroupListTest { + + private static final WifiP2pDevice TEST_GROUP_OWNER_1 = new WifiP2pDevice("aa:bb:cc:dd:ee:f0"); + private static final WifiP2pDevice TEST_GROUP_OWNER_2 = new WifiP2pDevice("aa:bb:cc:dd:ee:f1"); + private static final WifiP2pDevice TEST_GROUP_OWNER_3 = new WifiP2pDevice("aa:bb:cc:dd:ee:f2"); + private static final WifiP2pDevice TEST_GROUP_OWNER_OTHER = + new WifiP2pDevice("aa:bb:cc:dd:ee:f3"); + + private WifiP2pGroup mTestGroup1; + private WifiP2pGroup mTestGroup2; + private WifiP2pGroup mTestGroup3; + private WifiP2pGroup mTestGroup4; + + private WifiP2pGroup createGroup( + int networkId, String networkName, + String passphrase, boolean isGo, + WifiP2pDevice goDev) { + WifiP2pGroup group = new WifiP2pGroup(); + group.setNetworkId(networkId); + group.setNetworkName(networkName); + group.setPassphrase(passphrase); + group.setIsGroupOwner(isGo); + group.setOwner(goDev); + return group; + } + + @Before + public void setUp() throws Exception { + mTestGroup1 = createGroup(0, "testGroup1", "12345678", false, TEST_GROUP_OWNER_1); + mTestGroup2 = createGroup(1, "testGroup2", "12345678", true, TEST_GROUP_OWNER_2); + mTestGroup3 = createGroup(2, "testGroup3", "12345678", false, TEST_GROUP_OWNER_3); + mTestGroup4 = createGroup(3, "testGroup4", "12345678", false, TEST_GROUP_OWNER_1); + } + + /** + * Verify basic operations. + */ + @Test + public void testListOperations() throws Exception { + WifiP2pGroupList list = new WifiP2pGroupList(); + list.add(mTestGroup1); + list.add(mTestGroup2); + list.add(mTestGroup3); + list.add(mTestGroup4); + assertEquals(4, list.getGroupList().size()); + + // in list + assertEquals(mTestGroup2.getNetworkId(), + list.getNetworkId(TEST_GROUP_OWNER_2.deviceAddress)); + assertEquals(TEST_GROUP_OWNER_2.deviceAddress, + list.getOwnerAddr(mTestGroup2.getNetworkId())); + // not in list + assertEquals(-1, list.getNetworkId(TEST_GROUP_OWNER_OTHER.deviceAddress)); + // if there are groups with the same GO, return the first one found. + assertEquals(mTestGroup1.getNetworkId(), + list.getNetworkId(TEST_GROUP_OWNER_1.deviceAddress)); + // identify groups with the same GO, but different network names. + assertEquals(mTestGroup4.getNetworkId(), + list.getNetworkId(TEST_GROUP_OWNER_1.deviceAddress, "testGroup4")); + + list.remove(mTestGroup3.getNetworkId()); + assertEquals(-1, list.getNetworkId(TEST_GROUP_OWNER_3.deviceAddress)); + assertFalse(list.contains(mTestGroup3.getNetworkId())); + + assertEquals(3, list.getGroupList().size()); + + Parcel parcelW = Parcel.obtain(); + list.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiP2pGroupList fromParcel = WifiP2pGroupList.CREATOR.createFromParcel(parcelR); + + assertEquals(list.toString(), fromParcel.toString()); + + list.clear(); + assertEquals(0, list.getGroupList().size()); + + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pGroupTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pGroupTest.java new file mode 100644 index 000000000000..9473e42184e3 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pGroupTest.java @@ -0,0 +1,92 @@ +/* + * 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.net.wifi.p2p; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit test harness for {@link android.net.wifi.p2p.WifiP2pGroup} + */ +@SmallTest +public class WifiP2pGroupTest { + + private static final String INTERFACE = "p2p-p2p0-3"; + private static final int NETWORK_ID = 9; + private static final String NETWORK_NAME = "DIRECT-xy-Hello"; + private static final String PASSPHRASE = "HelloWorld"; + private static final WifiP2pDevice GROUP_OWNER = new WifiP2pDevice("de:ad:be:ef:00:01"); + private static final int FREQUENCY = 5300; + private static final WifiP2pDevice CLIENT_1 = new WifiP2pDevice("aa:bb:cc:dd:ee:01"); + private static final WifiP2pDevice CLIENT_2 = new WifiP2pDevice("aa:bb:cc:dd:ee:02"); + + /** + * Verify setter/getter functions. + */ + @Test + public void testSetterGetter() throws Exception { + WifiP2pGroup group = new WifiP2pGroup(); + + group.setInterface(INTERFACE); + group.setNetworkId(NETWORK_ID); + group.setNetworkName(NETWORK_NAME); + group.setPassphrase(PASSPHRASE); + group.setIsGroupOwner(false); + group.setOwner(GROUP_OWNER); + group.setFrequency(FREQUENCY); + group.addClient(CLIENT_1.deviceAddress); + group.addClient(CLIENT_2); + + assertEquals(INTERFACE, group.getInterface()); + assertEquals(NETWORK_ID, group.getNetworkId()); + assertEquals(NETWORK_NAME, group.getNetworkName()); + assertEquals(PASSPHRASE, group.getPassphrase()); + assertFalse(group.isGroupOwner()); + assertEquals(GROUP_OWNER, group.getOwner()); + assertEquals(FREQUENCY, group.getFrequency()); + + assertFalse(group.isClientListEmpty()); + assertTrue(group.contains(CLIENT_1)); + + assertEquals(2, group.getClientList().size()); + + group.removeClient(CLIENT_1); + group.removeClient(CLIENT_2.deviceAddress); + assertFalse(group.contains(CLIENT_1)); + assertTrue(group.isClientListEmpty()); + + Parcel parcelW = Parcel.obtain(); + group.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiP2pGroup fromParcel = WifiP2pGroup.CREATOR.createFromParcel(parcelR); + + assertEquals(group.toString(), fromParcel.toString()); + + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pInfoTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pInfoTest.java new file mode 100644 index 000000000000..e207ca1f3e7a --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pInfoTest.java @@ -0,0 +1,83 @@ +/* + * 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.net.wifi.p2p; + +import static org.junit.Assert.assertEquals; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +import java.net.InetAddress; + +/** + * Unit test harness for {@link android.net.wifi.p2p.WifiP2pInfo} + */ +@SmallTest +public class WifiP2pInfoTest { + + private InetAddress mGroupOnwerIpv4Address; + + @Before + public void setUp() throws Exception { + byte[] ipv4 = {(byte) 192, (byte) 168, (byte) 49, (byte) 1}; + mGroupOnwerIpv4Address = InetAddress.getByAddress(ipv4); + } + + /** + * Verifies copy constructor. + */ + @Test + public void testCopyOperator() throws Exception { + WifiP2pInfo info = new WifiP2pInfo(); + info.groupFormed = true; + info.isGroupOwner = true; + info.groupOwnerAddress = mGroupOnwerIpv4Address; + + WifiP2pInfo copiedInfo = new WifiP2pInfo(info); + + // no equals operator, use toString for data comparison. + assertEquals(info.toString(), copiedInfo.toString()); + } + + /** + * Verifies parcel serialization/deserialization. + */ + @Test + public void testParcelOperation() throws Exception { + WifiP2pInfo info = new WifiP2pInfo(); + info.groupFormed = true; + info.isGroupOwner = true; + info.groupOwnerAddress = mGroupOnwerIpv4Address; + + Parcel parcelW = Parcel.obtain(); + info.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiP2pInfo fromParcel = WifiP2pInfo.CREATOR.createFromParcel(parcelR); + + // no equals operator, use toString for data comparison. + assertEquals(info.toString(), fromParcel.toString()); + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pProvDiscEventTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pProvDiscEventTest.java new file mode 100644 index 000000000000..e3b10a7a52f0 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pProvDiscEventTest.java @@ -0,0 +1,111 @@ +/* + * 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.net.wifi.p2p; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit test harness for {@link android.net.wifi.p2p.WifiP2pProvDiscEvent} + */ +@SmallTest +public class WifiP2pProvDiscEventTest { + + private static final String DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff"; + private static final String EVENT_PBC_REQ_STRING = "P2P-PROV-DISC-PBC-REQ"; + private static final String EVENT_PBC_RSP_STRING = "P2P-PROV-DISC-PBC-RESP"; + private static final String EVENT_ENTER_PIN_STRING = "P2P-PROV-DISC-ENTER-PIN"; + private static final String EVENT_SHOW_PIN_STRING = "P2P-PROV-DISC-SHOW-PIN"; + private static final String TEST_PIN = "44490607"; + + /** + * Test parsing PBC request event. + */ + @Test + public void testPbcReqEvent() throws Exception { + WifiP2pProvDiscEvent event = + new WifiP2pProvDiscEvent(EVENT_PBC_REQ_STRING + " " + DEVICE_ADDRESS); + assertEquals(WifiP2pProvDiscEvent.PBC_REQ, event.event); + assertEquals(DEVICE_ADDRESS, event.device.deviceAddress); + } + + + /** + * Test parsing PBC response event. + */ + @Test + public void testPbcRespEvent() throws Exception { + WifiP2pProvDiscEvent event = + new WifiP2pProvDiscEvent(EVENT_PBC_RSP_STRING + " " + DEVICE_ADDRESS); + assertEquals(WifiP2pProvDiscEvent.PBC_RSP, event.event); + assertEquals(DEVICE_ADDRESS, event.device.deviceAddress); + } + + /** + * Test parsing ENTER-PIN event. + */ + @Test + public void testEnterPinEvent() throws Exception { + WifiP2pProvDiscEvent event = + new WifiP2pProvDiscEvent(EVENT_ENTER_PIN_STRING + " " + DEVICE_ADDRESS); + assertEquals(WifiP2pProvDiscEvent.ENTER_PIN, event.event); + assertEquals(DEVICE_ADDRESS, event.device.deviceAddress); + } + + /** + * Test parsing SHOW-PIN event. + */ + @Test + public void testShowPinEvent() throws Exception { + WifiP2pProvDiscEvent event = + new WifiP2pProvDiscEvent( + EVENT_SHOW_PIN_STRING + " " + DEVICE_ADDRESS + " " + TEST_PIN); + assertEquals(WifiP2pProvDiscEvent.SHOW_PIN, event.event); + assertEquals(DEVICE_ADDRESS, event.device.deviceAddress); + assertEquals(TEST_PIN, event.pin); + } + + /** + * Test parsing malformed input. + */ + @Test + public void testMalformedInput() throws Exception { + try { + WifiP2pProvDiscEvent event = new WifiP2pProvDiscEvent("OneToken"); + fail("Should throw IllegalArgumentException exception."); + } catch (IllegalArgumentException ex) { + // expected exception. + } + } + + /** + * Test parsing malformed event. + */ + @Test + public void testMalformedEvent() throws Exception { + try { + WifiP2pProvDiscEvent event = new WifiP2pProvDiscEvent("XXX " + DEVICE_ADDRESS); + fail("Should throw IllegalArgumentException exception."); + } catch (IllegalArgumentException ex) { + // expected exception. + } + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java new file mode 100644 index 000000000000..d2f11688e4e5 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java @@ -0,0 +1,110 @@ +/* + * 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.net.wifi.p2p; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +/** + * Unit test harness for {@link android.net.wifi.p2p.WifiP2pWfdInfo} + */ +@SmallTest +public class WifiP2pWfdInfoTest { + + private static final int TEST_CTRL_PORT = 9999; + private static final int TEST_MAX_TPUT = 1024; + + private WifiP2pWfdInfo mSourceInfo = new WifiP2pWfdInfo( + 0, + TEST_CTRL_PORT, + TEST_MAX_TPUT); + + @Before + public void setUp() { + // initialize device info flags. + mSourceInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE); + mSourceInfo.setSessionAvailable(true); + } + + /** + * Verifies setters/getters. + */ + @Test + public void testSettersGetters() throws Exception { + WifiP2pWfdInfo info = new WifiP2pWfdInfo(); + + info.setWfdEnabled(true); + assertTrue(info.isWfdEnabled()); + + info.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE); + assertEquals(WifiP2pWfdInfo.WFD_SOURCE, info.getDeviceType()); + + info.setCoupledSinkSupportAtSource(true); + assertTrue(info.isCoupledSinkSupportedAtSource()); + + info.setCoupledSinkSupportAtSink(true); + assertTrue(info.isCoupledSinkSupportedAtSink()); + + info.setSessionAvailable(true); + assertTrue(info.isSessionAvailable()); + + info.setControlPort(TEST_CTRL_PORT); + assertEquals(TEST_CTRL_PORT, info.getControlPort()); + + info.setMaxThroughput(TEST_MAX_TPUT); + assertEquals(TEST_MAX_TPUT, info.getMaxThroughput()); + + assertEquals("0018270f0400", info.getDeviceInfoHex()); + } + + /** + * Verifies copy constructor. + */ + @Test + public void testCopyOperator() throws Exception { + WifiP2pWfdInfo copiedInfo = new WifiP2pWfdInfo(mSourceInfo); + + // no equals operator, use toString for data comparison. + assertEquals(mSourceInfo.toString(), copiedInfo.toString()); + } + + /** + * Verifies parcel serialization/deserialization. + */ + @Test + public void testParcelOperation() throws Exception { + Parcel parcelW = Parcel.obtain(); + mSourceInfo.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiP2pWfdInfo fromParcel = WifiP2pWfdInfo.CREATOR.createFromParcel(parcelR); + + // no equals operator, use toString for data comparison. + assertEquals(mSourceInfo.toString(), fromParcel.toString()); + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfoTest.java b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfoTest.java new file mode 100644 index 000000000000..e1cffee361e8 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfoTest.java @@ -0,0 +1,88 @@ +/* + * 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.net.wifi.p2p.nsd; + +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * Unit test harness for {@link android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo} + */ +@SmallTest +public class WifiP2pDnsSdServiceInfoTest { + + private static final String INSTANCE_NAME = "MyPrinter"; + private static final String SERVICE_TYPE = "_ipp._tcp"; + private static final String TXTRECORD_PROP_AVAILABLE = "available"; + private static final String TXTRECORD_PROP_AVAILABLE_VISABLE = "visable"; + + private Map<String, String> mTxtMap = new HashMap<>(); + + @Before + public void setUp() throws Exception { + mTxtMap.put(TXTRECORD_PROP_AVAILABLE, TXTRECORD_PROP_AVAILABLE_VISABLE); + } + + /** + * Verify newInstance API + */ + @Test + public void testNewInstance() throws Exception { + WifiP2pDnsSdServiceInfo info = null; + + // the least arguments + info = WifiP2pDnsSdServiceInfo.newInstance( + INSTANCE_NAME, + SERVICE_TYPE, + null); + + // all arguments are given. + info = WifiP2pDnsSdServiceInfo.newInstance( + INSTANCE_NAME, + SERVICE_TYPE, + mTxtMap); + + // failure case due to no instance name. + try { + info = WifiP2pDnsSdServiceInfo.newInstance( + null, + SERVICE_TYPE, + null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + + // failure case due to no service type. + try { + info = WifiP2pDnsSdServiceInfo.newInstance( + INSTANCE_NAME, + null, + null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequestTest.java b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequestTest.java new file mode 100644 index 000000000000..7d46a5f3a79d --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequestTest.java @@ -0,0 +1,72 @@ +/* + * 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.net.wifi.p2p.nsd; + +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit test harness for {@link android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest} + */ +@SmallTest +public class WifiP2pDnsSdServiceRequestTest { + + private static final String SERVICE_NAME = "MyPrinter"; + private static final String SERVICE_TYPE = "_ipp._tcp"; + + @Test + public void testNewInstance() throws Exception { + WifiP2pDnsSdServiceRequest request = null; + + // default new instance + request = WifiP2pDnsSdServiceRequest.newInstance(); + + // set service type + request = WifiP2pDnsSdServiceRequest.newInstance(SERVICE_TYPE); + + // set service type + request = WifiP2pDnsSdServiceRequest.newInstance(SERVICE_NAME, SERVICE_TYPE); + + // failure case due to null service type + try { + request = WifiP2pDnsSdServiceRequest.newInstance(null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + + // failure case due to null service name + try { + request = WifiP2pDnsSdServiceRequest.newInstance(SERVICE_NAME, null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + + // failure case due to null service type + try { + request = WifiP2pDnsSdServiceRequest.newInstance(null, SERVICE_TYPE); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfoTest.java b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfoTest.java new file mode 100644 index 000000000000..49ead11065ae --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfoTest.java @@ -0,0 +1,80 @@ +/* + * 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.net.wifi.p2p.nsd; + +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit test harness for {@link android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo} + */ +@SmallTest +public class WifiP2pUpnpServiceInfoTest { + + private static final String UUID = "6859dede-8574-59ab-9332-123456789012"; + private static final String DEVICE = "aa:bb:cc:dd:ee:ff"; + + private List<String> mServiceList = new ArrayList<>(); + + @Before + public void setUp() throws Exception { + mServiceList.add("urn:schemas-upnp-org:service:ContentDirectory:1"); + } + + /** + * Verify newInstance API + */ + @Test + public void testNewInstance() throws Exception { + WifiP2pUpnpServiceInfo info = null; + + // the least arguments + info = WifiP2pUpnpServiceInfo.newInstance( + UUID, DEVICE, null); + + // all arguments are given. + info = WifiP2pUpnpServiceInfo.newInstance( + UUID, DEVICE, mServiceList); + + // failure case due to no UUID. + try { + info = WifiP2pUpnpServiceInfo.newInstance( + null, DEVICE, null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + + // failure case due to no device. + try { + info = WifiP2pUpnpServiceInfo.newInstance( + UUID, + null, + null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + } +} diff --git a/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequestTest.java b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequestTest.java new file mode 100644 index 000000000000..79930dc83372 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequestTest.java @@ -0,0 +1,49 @@ +/* + * 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.net.wifi.p2p.nsd; + +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit test harness for {@link android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest} + */ +@SmallTest +public class WifiP2pUpnpServiceRequestTest { + + @Test + public void testNewInstance() throws Exception { + WifiP2pUpnpServiceRequest request = null; + + // Create a service discovery request to search all UPnP services. + request = WifiP2pUpnpServiceRequest.newInstance(); + + // Create a service discovery request to search specified UPnP services. + request = WifiP2pUpnpServiceRequest.newInstance("ssdp:all"); + + // failure case due to null target string + try { + request = WifiP2pUpnpServiceRequest.newInstance(null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected exception. + } + } +} |