diff options
316 files changed, 5360 insertions, 2360 deletions
diff --git a/Android.bp b/Android.bp index c97ee3da36e4..9077344adf21 100644 --- a/Android.bp +++ b/Android.bp @@ -352,12 +352,8 @@ java_defaults { "core/java/android/service/chooser/IChooserTargetResult.aidl", "core/java/android/service/resolver/IResolverRankerService.aidl", "core/java/android/service/resolver/IResolverRankerResult.aidl", - "core/java/android/service/textclassifier/IConversationActionsCallback.aidl", - "core/java/android/service/textclassifier/ITextClassificationCallback.aidl", + "core/java/android/service/textclassifier/ITextClassifierCallback.aidl", "core/java/android/service/textclassifier/ITextClassifierService.aidl", - "core/java/android/service/textclassifier/ITextLanguageCallback.aidl", - "core/java/android/service/textclassifier/ITextLinksCallback.aidl", - "core/java/android/service/textclassifier/ITextSelectionCallback.aidl", "core/java/android/service/attention/IAttentionService.aidl", "core/java/android/service/attention/IAttentionCallback.aidl", "core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl", diff --git a/api/current.txt b/api/current.txt index 2156867ceb43..20ea9f1b109e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4447,7 +4447,7 @@ package android.app { public final class AutomaticZenRule implements android.os.Parcelable { ctor @Deprecated public AutomaticZenRule(String, android.content.ComponentName, android.net.Uri, int, boolean); - ctor public AutomaticZenRule(String, android.content.ComponentName, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, int, boolean); + ctor public AutomaticZenRule(@NonNull String, @Nullable android.content.ComponentName, @Nullable android.content.ComponentName, @NonNull android.net.Uri, @Nullable android.service.notification.ZenPolicy, int, boolean); ctor public AutomaticZenRule(android.os.Parcel); method public int describeContents(); method public android.net.Uri getConditionId(); @@ -10638,9 +10638,9 @@ package android.content { } public final class LocusId implements android.os.Parcelable { - ctor public LocusId(@NonNull android.net.Uri); + ctor public LocusId(@NonNull String); method public int describeContents(); - method @NonNull public android.net.Uri getUri(); + method @NonNull public String getId(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.LocusId> CREATOR; } @@ -14113,14 +14113,14 @@ package android.graphics { public class HardwareRenderer { ctor public HardwareRenderer(); method public void clearContent(); - method public android.graphics.HardwareRenderer.FrameRenderRequest createRenderRequest(); + method @NonNull public android.graphics.HardwareRenderer.FrameRenderRequest createRenderRequest(); method public void destroy(); method public boolean isOpaque(); method public void notifyFramePending(); method public void setContentRoot(@Nullable android.graphics.RenderNode); method public void setLightSourceAlpha(@FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float); method public void setLightSourceGeometry(float, float, float, float); - method public void setName(String); + method public void setName(@NonNull String); method public void setOpaque(boolean); method public void setStopped(boolean); method public void setSurface(@Nullable android.view.Surface); @@ -14132,9 +14132,9 @@ package android.graphics { } public final class HardwareRenderer.FrameRenderRequest { - method public android.graphics.HardwareRenderer.FrameRenderRequest setFrameCommitCallback(@NonNull java.util.concurrent.Executor, @NonNull Runnable); - method public android.graphics.HardwareRenderer.FrameRenderRequest setVsyncTime(long); - method public android.graphics.HardwareRenderer.FrameRenderRequest setWaitForPresent(boolean); + method @NonNull public android.graphics.HardwareRenderer.FrameRenderRequest setFrameCommitCallback(@NonNull java.util.concurrent.Executor, @NonNull Runnable); + method @NonNull public android.graphics.HardwareRenderer.FrameRenderRequest setVsyncTime(long); + method @NonNull public android.graphics.HardwareRenderer.FrameRenderRequest setWaitForPresent(boolean); method public int syncAndDraw(); } @@ -14156,6 +14156,7 @@ package android.graphics { method @Nullable public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener(); method @Nullable public android.graphics.PostProcessor getPostProcessor(); method public boolean isDecodeAsAlphaMaskEnabled(); + method public static boolean isMimeTypeSupported(@NonNull String); method public boolean isMutableRequired(); method public boolean isUnpremultipliedRequired(); method public void setAllocator(int); @@ -14952,8 +14953,8 @@ package android.graphics { public final class RenderNode { ctor public RenderNode(@Nullable String); - method public android.graphics.RecordingCanvas beginRecording(int, int); - method public android.graphics.RecordingCanvas beginRecording(); + method @NonNull public android.graphics.RecordingCanvas beginRecording(int, int); + method @NonNull public android.graphics.RecordingCanvas beginRecording(); method public long computeApproximateMemoryUsage(); method public void discardDisplayList(); method public void endRecording(); @@ -15006,7 +15007,7 @@ package android.graphics { method public boolean setPivotX(float); method public boolean setPivotY(float); method public boolean setPosition(int, int, int, int); - method public boolean setPosition(android.graphics.Rect); + method public boolean setPosition(@NonNull android.graphics.Rect); method public boolean setProjectBackwards(boolean); method public boolean setProjectionReceiver(boolean); method public boolean setRotationX(float); @@ -15689,10 +15690,10 @@ package android.graphics.drawable { public class StateListDrawable extends android.graphics.drawable.DrawableContainer { ctor public StateListDrawable(); method public void addState(int[], android.graphics.drawable.Drawable); - method public int findStateDrawableIndex(int[]); + method public int findStateDrawableIndex(@NonNull int[]); method public int getStateCount(); - method public android.graphics.drawable.Drawable getStateDrawable(int); - method public int[] getStateSet(int); + method @Nullable public android.graphics.drawable.Drawable getStateDrawable(int); + method @NonNull public int[] getStateSet(int); } public class TransitionDrawable extends android.graphics.drawable.LayerDrawable implements android.graphics.drawable.Drawable.Callback { @@ -16797,6 +16798,7 @@ package android.hardware.camera2 { public abstract static class CameraManager.AvailabilityCallback { ctor public CameraManager.AvailabilityCallback(); + method public void onCameraAccessPrioritiesChanged(); method public void onCameraAvailable(@NonNull String); method public void onCameraUnavailable(@NonNull String); } @@ -22857,7 +22859,6 @@ package android.location { method public float getBearing(); method public float getBearingAccuracyDegrees(); method public long getElapsedRealtimeNanos(); - method public long getElapsedRealtimeUncertaintyNanos(); method public android.os.Bundle getExtras(); method public double getLatitude(); method public double getLongitude(); @@ -22870,7 +22871,6 @@ package android.location { method public boolean hasAltitude(); method public boolean hasBearing(); method public boolean hasBearingAccuracy(); - method public boolean hasElapsedRealtimeUncertaintyNanos(); method public boolean hasSpeed(); method public boolean hasSpeedAccuracy(); method public boolean hasVerticalAccuracy(); @@ -22886,7 +22886,6 @@ package android.location { method public void setBearing(float); method public void setBearingAccuracyDegrees(float); method public void setElapsedRealtimeNanos(long); - method public void setElapsedRealtimeUncertaintyNanos(long); method public void setExtras(android.os.Bundle); method public void setLatitude(double); method public void setLongitude(double); @@ -23054,7 +23053,7 @@ package android.media { ctor public AudioAttributes.Builder(); ctor public AudioAttributes.Builder(android.media.AudioAttributes); method public android.media.AudioAttributes build(); - method public android.media.AudioAttributes.Builder setAllowCapture(boolean); + method @NonNull public android.media.AudioAttributes.Builder setAllowCapture(boolean); method public android.media.AudioAttributes.Builder setContentType(int); method public android.media.AudioAttributes.Builder setFlags(int); method public android.media.AudioAttributes.Builder setLegacyStreamType(int); @@ -23393,11 +23392,11 @@ package android.media { public static final class AudioPlaybackCaptureConfiguration.Builder { ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection); - method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int); - method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes); - method public android.media.AudioPlaybackCaptureConfiguration build(); - method public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int); - method public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(@NonNull android.media.AudioAttributes); + method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int); + method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes); + method @NonNull public android.media.AudioPlaybackCaptureConfiguration build(); + method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int); + method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(@NonNull android.media.AudioAttributes); } public final class AudioPlaybackConfiguration implements android.os.Parcelable { @@ -23498,7 +23497,7 @@ package android.media { ctor public AudioRecord.Builder(); method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException; method public android.media.AudioRecord.Builder setAudioFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException; - method public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration); + method @NonNull public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration); method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException; method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException; } @@ -23570,7 +23569,6 @@ package android.media { method @Deprecated public void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler); method public int attachAuxEffect(int); method @NonNull public android.media.VolumeShaper createVolumeShaper(@NonNull android.media.VolumeShaper.Configuration); - method @Deprecated public static void deprecateStreamTypeForPlayback(int, @NonNull String, @NonNull String) throws java.lang.IllegalArgumentException; method protected void finalize(); method public void flush(); method @NonNull public android.media.AudioAttributes getAudioAttributes(); @@ -23696,12 +23694,12 @@ package android.media { } public class CallbackDataSourceDesc extends android.media.DataSourceDesc { - method public android.media.DataSourceCallback getDataSourceCallback(); + method @NonNull public android.media.DataSourceCallback getDataSourceCallback(); } public static class CallbackDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.CallbackDataSourceDesc.Builder> { ctor public CallbackDataSourceDesc.Builder(); - ctor public CallbackDataSourceDesc.Builder(android.media.CallbackDataSourceDesc); + ctor public CallbackDataSourceDesc.Builder(@Nullable android.media.CallbackDataSourceDesc); method @NonNull public android.media.CallbackDataSourceDesc build(); method @NonNull public android.media.CallbackDataSourceDesc.Builder setDataSource(@NonNull android.media.DataSourceCallback); } @@ -23761,12 +23759,12 @@ package android.media { public abstract class DataSourceCallback implements java.io.Closeable { ctor public DataSourceCallback(); method public abstract long getSize() throws java.io.IOException; - method public abstract int readAt(long, byte[], int, int) throws java.io.IOException; + method public abstract int readAt(long, @NonNull byte[], int, int) throws java.io.IOException; } public class DataSourceDesc { method public long getEndPosition(); - method public String getMediaId(); + 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 @@ -23774,7 +23772,7 @@ package android.media { protected static class DataSourceDesc.BuilderBase<T extends android.media.DataSourceDesc.BuilderBase> { method @NonNull public T setEndPosition(long); - method @NonNull public T setMediaId(String); + method @NonNull public T setMediaId(@Nullable String); method @NonNull public T setStartPosition(long); } @@ -23983,13 +23981,13 @@ package android.media { public class FileDataSourceDesc extends android.media.DataSourceDesc { method public long getLength(); method public long getOffset(); - method public android.os.ParcelFileDescriptor getParcelFileDescriptor(); + method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor(); field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL } public static class FileDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.FileDataSourceDesc.Builder> { ctor public FileDataSourceDesc.Builder(); - ctor public FileDataSourceDesc.Builder(android.media.FileDataSourceDesc); + ctor public FileDataSourceDesc.Builder(@Nullable android.media.FileDataSourceDesc); method @NonNull public android.media.FileDataSourceDesc build(); method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor); method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long); @@ -25139,7 +25137,7 @@ package android.media { field public static final long POSITION_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL } - public static class MediaItem2.Builder { + 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); @@ -25327,7 +25325,6 @@ package android.media { method public static android.media.MediaPlayer create(android.content.Context, int); method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int); method @NonNull public android.media.VolumeShaper createVolumeShaper(@NonNull android.media.VolumeShaper.Configuration); - method @Deprecated public static void deprecateStreamTypeForPlayback(int, @NonNull String, @NonNull String) throws java.lang.IllegalArgumentException; method public void deselectTrack(int) throws java.lang.IllegalStateException; method protected void finalize(); method public int getAudioSessionId(); @@ -25541,16 +25538,16 @@ package android.media { } public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable { - ctor public MediaPlayer2(android.content.Context); - method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); - method public Object attachAuxEffect(int); + 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 public Object clearNextDataSources(); + method @NonNull public Object clearNextDataSources(); method public void clearPendingCommands(); method public void close(); - method public Object deselectTrack(int); - method public Object deselectTrack(@NonNull android.media.DataSourceDesc, int); + method @NonNull public Object deselectTrack(int); + method @NonNull public Object deselectTrack(@NonNull android.media.DataSourceDesc, int); method @NonNull public android.media.AudioAttributes getAudioAttributes(); method public int getAudioSessionId(); method public long getBufferedPosition(); @@ -25560,11 +25557,11 @@ package android.media { method public long getDuration(); method public long getDuration(@NonNull android.media.DataSourceDesc); method public float getMaxPlayerVolume(); - method public android.os.PersistableBundle getMetrics(); + method @Nullable public android.os.PersistableBundle getMetrics(); method @NonNull public android.media.PlaybackParams getPlaybackParams(); method public float getPlayerVolume(); - method public android.media.AudioDeviceInfo getPreferredDevice(); - method public android.media.AudioDeviceInfo getRoutedDevice(); + method @Nullable public android.media.AudioDeviceInfo getPreferredDevice(); + method @Nullable public android.media.AudioDeviceInfo getRoutedDevice(); method public int getSelectedTrack(int); method public int getSelectedTrack(@NonNull android.media.DataSourceDesc, int); method public int getState(); @@ -25572,37 +25569,37 @@ package android.media { 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 public android.util.Size getVideoSize(); + method @NonNull public android.util.Size getVideoSize(); method public boolean isLooping(); - method public Object loopCurrent(boolean); - method public Object notifyWhenCommandLabelReached(@NonNull Object); - method public Object pause(); - method public Object play(); - method public Object prepare(); + 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(android.media.AudioRouting.OnRoutingChangedListener); + method public void removeOnRoutingChangedListener(@NonNull android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); - method public Object seekTo(long); - method public Object seekTo(long, int); - method public Object selectTrack(int); - method public Object selectTrack(@NonNull android.media.DataSourceDesc, int); - method public Object setAudioAttributes(@NonNull android.media.AudioAttributes); - method public Object setAudioSessionId(int); - method public Object setAuxEffectSendLevel(float); - method public Object setDataSource(@NonNull android.media.DataSourceDesc); - method public Object setDisplay(android.view.SurfaceHolder); + method @NonNull public Object seekTo(long); + method @NonNull public Object seekTo(long, int); + method @NonNull public Object selectTrack(int); + method @NonNull public Object selectTrack(@NonNull android.media.DataSourceDesc, int); + 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 public Object setNextDataSource(@NonNull android.media.DataSourceDesc); - method public Object setNextDataSources(@NonNull java.util.List<android.media.DataSourceDesc>); - method public Object setPlaybackParams(@NonNull android.media.PlaybackParams); - method public Object setPlayerVolume(float); - method public boolean setPreferredDevice(android.media.AudioDeviceInfo); - method public Object setScreenOnWhilePlaying(boolean); - method public Object setSurface(android.view.Surface); - method public Object setSyncParams(@NonNull android.media.SyncParams); - method public Object setWakeLock(@NonNull android.os.PowerManager.WakeLock); - method public Object skipToNext(); - method public void unregisterEventCallback(android.media.MediaPlayer2.EventCallback); + 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 @@ -25737,8 +25734,8 @@ package android.media { } public static class MediaPlayer2.TrackInfo { - method public android.media.MediaFormat getFormat(); - method public String getLanguage(); + method @Nullable public android.media.MediaFormat getFormat(); + method @Nullable 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 @@ -26422,7 +26419,6 @@ package android.media { ctor @Deprecated public SoundPool(int, int, int); method public final void autoPause(); method public final void autoResume(); - method @Deprecated public static void deprecateStreamTypeForPlayback(int, @NonNull String, @NonNull String) throws java.lang.IllegalArgumentException; method protected void finalize(); method public int load(String, int); method public int load(android.content.Context, int, int); @@ -26618,15 +26614,15 @@ package android.media { } public class UriDataSourceDesc extends android.media.DataSourceDesc { - method public android.content.Context getContext(); - method public java.util.List<java.net.HttpCookie> getCookies(); - method public java.util.Map<java.lang.String,java.lang.String> getHeaders(); - method public android.net.Uri getUri(); + method @NonNull public android.content.Context getContext(); + 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 class UriDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.UriDataSourceDesc.Builder> { ctor public UriDataSourceDesc.Builder(); - ctor public UriDataSourceDesc.Builder(android.media.UriDataSourceDesc); + ctor public UriDataSourceDesc.Builder(@Nullable android.media.UriDataSourceDesc); method @NonNull public android.media.UriDataSourceDesc build(); method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri); method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>); @@ -28981,6 +28977,7 @@ package android.net { field public static final int NET_CAPABILITY_IA = 7; // 0x7 field public static final int NET_CAPABILITY_IMS = 4; // 0x4 field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc + field public static final int NET_CAPABILITY_MCX = 23; // 0x17 field public static final int NET_CAPABILITY_MMS = 0; // 0x0 field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14 field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb @@ -38420,7 +38417,8 @@ package android.provider { method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri); method public static android.net.Uri getMediaScannerUri(); method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri); - method public static String getVersion(android.content.Context); + method @NonNull public static String getVersion(@NonNull android.content.Context); + method @NonNull public static String getVersion(@NonNull android.content.Context, @NonNull String); method @NonNull public static String getVolumeName(@NonNull android.net.Uri); method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri); method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri); @@ -41871,26 +41869,26 @@ package android.service.notification { public static class ZenPolicy.Builder { ctor public ZenPolicy.Builder(); - method public android.service.notification.ZenPolicy.Builder allowAlarms(boolean); - method public android.service.notification.ZenPolicy.Builder allowAllSounds(); - method public android.service.notification.ZenPolicy.Builder allowCalls(int); - method public android.service.notification.ZenPolicy.Builder allowEvents(boolean); - method public android.service.notification.ZenPolicy.Builder allowMedia(boolean); - method public android.service.notification.ZenPolicy.Builder allowMessages(int); - method public android.service.notification.ZenPolicy.Builder allowReminders(boolean); - method public android.service.notification.ZenPolicy.Builder allowRepeatCallers(boolean); - method public android.service.notification.ZenPolicy.Builder allowSystem(boolean); - method public android.service.notification.ZenPolicy build(); - method public android.service.notification.ZenPolicy.Builder disallowAllSounds(); - method public android.service.notification.ZenPolicy.Builder hideAllVisualEffects(); - method public android.service.notification.ZenPolicy.Builder showAllVisualEffects(); - method public android.service.notification.ZenPolicy.Builder showBadges(boolean); - method public android.service.notification.ZenPolicy.Builder showFullScreenIntent(boolean); - method public android.service.notification.ZenPolicy.Builder showInAmbientDisplay(boolean); - method public android.service.notification.ZenPolicy.Builder showInNotificationList(boolean); - method public android.service.notification.ZenPolicy.Builder showLights(boolean); - method public android.service.notification.ZenPolicy.Builder showPeeking(boolean); - method public android.service.notification.ZenPolicy.Builder showStatusBarIcons(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder allowAlarms(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder allowAllSounds(); + method @NonNull public android.service.notification.ZenPolicy.Builder allowCalls(int); + method @NonNull public android.service.notification.ZenPolicy.Builder allowEvents(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder allowMedia(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder allowMessages(int); + method @NonNull public android.service.notification.ZenPolicy.Builder allowReminders(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder allowRepeatCallers(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder allowSystem(boolean); + method @NonNull public android.service.notification.ZenPolicy build(); + method @NonNull public android.service.notification.ZenPolicy.Builder disallowAllSounds(); + method @NonNull public android.service.notification.ZenPolicy.Builder hideAllVisualEffects(); + method @NonNull public android.service.notification.ZenPolicy.Builder showAllVisualEffects(); + method @NonNull public android.service.notification.ZenPolicy.Builder showBadges(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder showFullScreenIntent(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder showInAmbientDisplay(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder showInNotificationList(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder showLights(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder showPeeking(boolean); + method @NonNull public android.service.notification.ZenPolicy.Builder showStatusBarIcons(boolean); } } @@ -45146,8 +45144,8 @@ package android.telephony { method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei(int); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}) public String getLine1Number(); - method public String getManufacturerCode(); - method public String getManufacturerCode(int); + method @Nullable public String getManufacturerCode(); + method @Nullable public String getManufacturerCode(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(int); method public String getMmsUAProfUrl(); @@ -45174,8 +45172,8 @@ package android.telephony { method public int getSimState(); method public int getSimState(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSubscriberId(); - method public String getTypeAllocationCode(); - method public String getTypeAllocationCode(int); + method @Nullable public String getTypeAllocationCode(); + method @Nullable public String getTypeAllocationCode(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @NonNull public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag(); @@ -45471,6 +45469,7 @@ package android.telephony.data { field public static final int TYPE_HIPRI = 16; // 0x10 field public static final int TYPE_IA = 256; // 0x100 field public static final int TYPE_IMS = 64; // 0x40 + field public static final int TYPE_MCX = 1024; // 0x400 field public static final int TYPE_MMS = 2; // 0x2 field public static final int TYPE_SUPL = 4; // 0x4 } @@ -45560,7 +45559,7 @@ package android.telephony.euicc { } public class EuiccManager { - method public android.telephony.euicc.EuiccManager createForCardId(int); + method @NonNull public android.telephony.euicc.EuiccManager createForCardId(int); method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void deleteSubscription(int, android.app.PendingIntent); method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent); method @Nullable public String getEid(); @@ -47113,7 +47112,7 @@ package android.text.style { public static class LineHeightSpan.Standard implements android.text.style.LineHeightSpan android.text.ParcelableSpan { ctor public LineHeightSpan.Standard(@Px @IntRange(from=1) int); - ctor public LineHeightSpan.Standard(android.os.Parcel); + ctor public LineHeightSpan.Standard(@NonNull android.os.Parcel); method public void chooseHeight(@NonNull CharSequence, int, int, int, int, @NonNull android.graphics.Paint.FontMetricsInt); method public int describeContents(); method @Px public int getHeight(); @@ -51973,6 +51972,7 @@ package android.view { method public int getStableInsetRight(); method public int getStableInsetTop(); method @NonNull public android.graphics.Insets getStableInsets(); + method @NonNull public android.graphics.Insets getSystemGestureInsets(); method public int getSystemWindowInsetBottom(); method public int getSystemWindowInsetLeft(); method public int getSystemWindowInsetRight(); @@ -51994,6 +51994,7 @@ package android.view { method @NonNull public android.view.WindowInsets build(); method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout); method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets); + method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets); method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets); } @@ -53037,7 +53038,7 @@ package android.view.contentcapture { public final class ContentCaptureContext implements android.os.Parcelable { method public int describeContents(); - method @NonNull public static android.view.contentcapture.ContentCaptureContext forLocusId(@NonNull android.net.Uri); + method @NonNull public static android.view.contentcapture.ContentCaptureContext forLocusId(@NonNull String); method @Nullable public android.os.Bundle getExtras(); method @NonNull public android.content.LocusId getLocusId(); method public void writeToParcel(android.os.Parcel, int); @@ -53085,18 +53086,19 @@ package android.view.contentcapture { 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 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, boolean); + 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 final class UserDataRemovalRequest.LocusIdRequest { + method @NonNull public int getFlags(); method @NonNull public android.content.LocusId getLocusId(); - method @NonNull public boolean isRecursive(); } } @@ -57332,7 +57334,7 @@ package android.widget { method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier(); method public final android.content.res.ColorStateList getTextColors(); method @Nullable public android.graphics.drawable.Drawable getTextCursorDrawable(); - method public android.text.TextDirectionHeuristic getTextDirectionHeuristic(); + method @NonNull public android.text.TextDirectionHeuristic getTextDirectionHeuristic(); method @NonNull public java.util.Locale getTextLocale(); method @NonNull @Size(min=1) public android.os.LocaleList getTextLocales(); method @NonNull public android.text.PrecomputedText.Params getTextMetricsParams(); diff --git a/api/system-current.txt b/api/system-current.txt index 04e818b07c42..7518bb795b97 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -25,6 +25,7 @@ package android { field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE"; field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE"; field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE"; + field public static final String BIND_CONTENT_SUGGESTIONS_SERVICE = "android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE"; field public static final String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH"; field public static final String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE"; field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE"; @@ -182,6 +183,7 @@ package android { field public static final String SHUTDOWN = "android.permission.SHUTDOWN"; field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES"; field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"; + field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED"; field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE"; @@ -952,7 +954,7 @@ package android.app.contentsuggestions { public final class ClassificationsRequest implements android.os.Parcelable { method public int describeContents(); - method @Nullable public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method @NonNull public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ClassificationsRequest> CREATOR; @@ -960,8 +962,8 @@ package android.app.contentsuggestions { public static final class ClassificationsRequest.Builder { ctor public ClassificationsRequest.Builder(@NonNull java.util.List<android.app.contentsuggestions.ContentSelection>); - method public android.app.contentsuggestions.ClassificationsRequest build(); - method public android.app.contentsuggestions.ClassificationsRequest.Builder setExtras(@NonNull android.os.Bundle); + method @NonNull public android.app.contentsuggestions.ClassificationsRequest build(); + method @NonNull public android.app.contentsuggestions.ClassificationsRequest.Builder setExtras(@NonNull android.os.Bundle); } public final class ContentClassification implements android.os.Parcelable { @@ -999,7 +1001,7 @@ package android.app.contentsuggestions { public final class SelectionsRequest implements android.os.Parcelable { method public int describeContents(); - method @Nullable public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method @Nullable public android.graphics.Point getInterestPoint(); method public int getTaskId(); method public void writeToParcel(android.os.Parcel, int); @@ -1008,9 +1010,9 @@ package android.app.contentsuggestions { public static final class SelectionsRequest.Builder { ctor public SelectionsRequest.Builder(int); - method public android.app.contentsuggestions.SelectionsRequest build(); - method public android.app.contentsuggestions.SelectionsRequest.Builder setExtras(@NonNull android.os.Bundle); - method public android.app.contentsuggestions.SelectionsRequest.Builder setInterestPoint(@NonNull android.graphics.Point); + method @NonNull public android.app.contentsuggestions.SelectionsRequest build(); + method @NonNull public android.app.contentsuggestions.SelectionsRequest.Builder setExtras(@NonNull android.os.Bundle); + method @NonNull public android.app.contentsuggestions.SelectionsRequest.Builder setInterestPoint(@NonNull android.graphics.Point); } } @@ -1188,7 +1190,7 @@ package android.app.usage { method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String); method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets(); method public int getUsageSource(); - method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @Nullable android.app.PendingIntent); + 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 @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 public void reportUsageStart(@NonNull android.app.Activity, @NonNull String); @@ -3541,7 +3543,7 @@ package android.media { method public void stop(); } - public static class HwAudioSource.Builder { + public static final class HwAudioSource.Builder { ctor public HwAudioSource.Builder(); method @NonNull public android.media.HwAudioSource build(); method @NonNull public android.media.HwAudioSource.Builder setAudioAttributes(@NonNull android.media.AudioAttributes); @@ -3554,7 +3556,7 @@ package android.media { field public static final int RADIO_TUNER = 1998; // 0x7ce } - public static class MediaTimestamp.Builder { + public static final class MediaTimestamp.Builder { ctor public MediaTimestamp.Builder(); ctor public MediaTimestamp.Builder(@NonNull android.media.MediaTimestamp); method @NonNull public android.media.MediaTimestamp build(); @@ -3570,14 +3572,14 @@ package android.media { method public void stop(); } - public static class SubtitleData.Builder { + public static final class SubtitleData.Builder { ctor public SubtitleData.Builder(); ctor public SubtitleData.Builder(@NonNull android.media.SubtitleData); method @NonNull public android.media.SubtitleData build(); method @NonNull public android.media.SubtitleData.Builder setSubtitleData(int, long, long, @NonNull byte[]); } - public static class TimedMetaData.Builder { + public static final class TimedMetaData.Builder { ctor public TimedMetaData.Builder(); ctor public TimedMetaData.Builder(@NonNull android.media.TimedMetaData); method @NonNull public android.media.TimedMetaData build(); @@ -3679,7 +3681,7 @@ package android.media.audiopolicy { 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 public java.util.Iterator<android.media.audiopolicy.AudioProductStrategy> iterator(); + 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; @@ -3696,7 +3698,7 @@ package android.media.audiopolicy { public final class AudioVolumeGroup implements android.os.Parcelable { method public int describeContents(); - method public java.util.List<android.media.AudioAttributes> getAudioAttributes(); + method @NonNull public java.util.List<android.media.AudioAttributes> getAudioAttributes(); method public int getId(); method @NonNull public int[] getLegacyStreamTypes(); method @NonNull public String name(); @@ -3708,7 +3710,7 @@ package android.media.audiopolicy { ctor public AudioVolumeGroups(); method public int describeContents(); method @Nullable public android.media.audiopolicy.AudioVolumeGroup getById(int); - method public java.util.Iterator<android.media.audiopolicy.AudioVolumeGroup> iterator(); + 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; @@ -5689,6 +5691,7 @@ package android.permission { method @NonNull public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> onGetPermissionUsages(boolean, long); method public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream); method public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String); + method public abstract boolean onIsRoleVisible(@NonNull String); method @BinderThread public abstract boolean onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle); method @BinderThread public abstract void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream); method public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String); @@ -5708,7 +5711,7 @@ package android.permission { } public final class RuntimePermissionPresentationInfo implements android.os.Parcelable { - ctor public RuntimePermissionPresentationInfo(CharSequence, boolean, boolean); + ctor public RuntimePermissionPresentationInfo(@NonNull CharSequence, boolean, boolean); method public int describeContents(); method @NonNull public CharSequence getLabel(); method public boolean isGranted(); @@ -5852,19 +5855,17 @@ package android.provider { 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(String, String, String, boolean); field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; + field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot"; field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; field public static final String NAMESPACE_GAME_DRIVER = "game_driver"; field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot"; + field public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; field public static final String NAMESPACE_NETD_NATIVE = "netd_native"; + field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot"; field public static final String NAMESPACE_SYSTEMUI = "systemui"; } - public static interface DeviceConfig.ActivityManagerNativeBoot { - field public static final String NAMESPACE = "activity_manager_native_boot"; - field public static final String OFFLOAD_QUEUE_ENABLED = "offload_queue_enabled"; - } - public static interface DeviceConfig.AttentionManagerService { field public static final String COMPONENT_NAME = "component_name"; field public static final String NAMESPACE = "attention_manager_service"; @@ -5883,10 +5884,6 @@ package android.provider { field public static final String NAMESPACE = "intelligence_attention"; } - public static interface DeviceConfig.MediaNative { - field public static final String NAMESPACE = "media_native"; - } - public static interface DeviceConfig.OnPropertyChangedListener { method public void onPropertyChanged(String, String, String); } @@ -5913,10 +5910,6 @@ package android.provider { field public static final String NAMESPACE = "runtime_native"; } - public static interface DeviceConfig.RuntimeNativeBoot { - field public static final String NAMESPACE = "runtime_native_boot"; - } - public static interface DeviceConfig.Scheduler { field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection"; field public static final String NAMESPACE = "scheduler"; @@ -6434,8 +6427,8 @@ package android.service.carrier { public abstract class ApnService extends android.app.Service { ctor public ApnService(); - method public android.os.IBinder onBind(android.content.Intent); - method @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int); + method @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent); + method @WorkerThread @NonNull public abstract java.util.List<android.content.ContentValues> onRestoreApns(int); } } @@ -6772,15 +6765,15 @@ package android.service.textclassifier { method 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 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>); - method public void onCreateTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext, @NonNull android.view.textclassifier.TextClassificationSessionId); - method public void onDestroyTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationSessionId); - method public void onDetectLanguage(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLanguage.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLanguage>); - method public abstract void onGenerateLinks(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLinks.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>); - method @Deprecated public void onSelectionEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.SelectionEvent); - method public void onSuggestConversationActions(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.ConversationActions.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.ConversationActions>); - method public abstract void onSuggestSelection(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextSelection.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextSelection>); - method public void onTextClassifierEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassifierEvent); + 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>); + method @MainThread public void onCreateTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext, @NonNull android.view.textclassifier.TextClassificationSessionId); + method @MainThread public void onDestroyTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationSessionId); + method @MainThread public void onDetectLanguage(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLanguage.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLanguage>); + method @MainThread public abstract void onGenerateLinks(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLinks.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>); + method @Deprecated @MainThread public void onSelectionEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.SelectionEvent); + method @MainThread public void onSuggestConversationActions(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.ConversationActions.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.ConversationActions>); + method @MainThread public abstract void onSuggestSelection(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextSelection.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextSelection>); + method @MainThread public void onTextClassifierEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassifierEvent); field public static final String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService"; } @@ -7107,12 +7100,12 @@ package android.telephony { field public static final int WWAN = 1; // 0x1 } - public class CallAttributes implements android.os.Parcelable { - ctor public CallAttributes(android.telephony.PreciseCallState, int, android.telephony.CallQuality); + public final class CallAttributes implements android.os.Parcelable { + ctor public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality); method public int describeContents(); - method public android.telephony.CallQuality getCallQuality(); + method @NonNull public android.telephony.CallQuality getCallQuality(); method public int getNetworkType(); - method public android.telephony.PreciseCallState getPreciseCallState(); + method @NonNull public android.telephony.PreciseCallState getPreciseCallState(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR; } @@ -7149,13 +7142,13 @@ package android.telephony { } public final class CarrierRestrictionRules implements android.os.Parcelable { + method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); method public int describeContents(); method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(); method public int getDefaultCarrierRestriction(); method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers(); method public int getMultiSimPolicy(); method public boolean isAllCarriersAllowed(); - method public java.util.List<java.lang.Boolean> isCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); method public void writeToParcel(android.os.Parcel, int); field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1 field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0 @@ -7164,13 +7157,13 @@ package android.telephony { field public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1; // 0x1 } - public static class CarrierRestrictionRules.Builder { - method public android.telephony.CarrierRestrictionRules build(); - method public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed(); - method public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>); - method public android.telephony.CarrierRestrictionRules.Builder setDefaultCarrierRestriction(int); - method public android.telephony.CarrierRestrictionRules.Builder setExcludedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>); - method public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int); + public static final class 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>); + method @NonNull public android.telephony.CarrierRestrictionRules.Builder setDefaultCarrierRestriction(int); + method @NonNull public android.telephony.CarrierRestrictionRules.Builder setExcludedCarriers(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); + method @NonNull public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int); } public final class DataFailCause { @@ -7960,7 +7953,7 @@ package android.telephony { method @Deprecated public boolean getDataEnabled(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getLogicalToPhysicalSlotMapping(); method public static long getMaxNumberVerificationTimeoutMillis(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmap(); @@ -8436,7 +8429,7 @@ package android.telephony.ims { } public class ImsCallSessionListener { - method public void callQualityChanged(android.telephony.CallQuality); + method public void callQualityChanged(@NonNull android.telephony.CallQuality); method public void callSessionConferenceExtendFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); @@ -8461,7 +8454,7 @@ package android.telephony.ims { method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile); method public void callSessionResumed(android.telephony.ims.ImsCallProfile); - method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile); + method public void callSessionRttAudioIndicatorChanged(@NonNull android.telephony.ims.ImsStreamMediaProfile); method public void callSessionRttMessageReceived(String); method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile); method public void callSessionRttModifyResponseReceived(int); @@ -8765,12 +8758,12 @@ package android.telephony.ims { public final class ImsSsData implements android.os.Parcelable { ctor public ImsSsData(int, int, int, int, int); method public int describeContents(); - method public android.telephony.ims.ImsCallForwardInfo[] getCallForwardInfo(); + method @Nullable public java.util.List<android.telephony.ims.ImsCallForwardInfo> getCallForwardInfo(); method public int getRequestType(); method public int getResult(); method public int getServiceClass(); method public int getServiceType(); - method @NonNull public android.telephony.ims.ImsSsInfo[] getSuppServiceInfo(); + method @NonNull public java.util.List<android.telephony.ims.ImsSsInfo> getSuppServiceInfo(); method public int getTeleserviceType(); method public boolean isTypeBarring(); method public boolean isTypeCf(); @@ -8830,11 +8823,11 @@ package android.telephony.ims { field public static final int SS_WAIT = 12; // 0xc } - public static class ImsSsData.Builder { + public static final class ImsSsData.Builder { ctor public ImsSsData.Builder(int, int, int, int, int); method @NonNull public android.telephony.ims.ImsSsData build(); - method @NonNull public android.telephony.ims.ImsSsData.Builder setCallForwardingInfo(@NonNull android.telephony.ims.ImsCallForwardInfo[]); - method @NonNull public android.telephony.ims.ImsSsData.Builder setSuppServiceInfo(@NonNull android.telephony.ims.ImsSsInfo[]); + method @NonNull public android.telephony.ims.ImsSsData.Builder setCallForwardingInfo(@NonNull java.util.List<android.telephony.ims.ImsCallForwardInfo>); + method @NonNull public android.telephony.ims.ImsSsData.Builder setSuppServiceInfo(@NonNull java.util.List<android.telephony.ims.ImsSsInfo>); } public final class ImsSsInfo implements android.os.Parcelable { @@ -8843,7 +8836,7 @@ package android.telephony.ims { method public int getClirInterrogationStatus(); method public int getClirOutgoingState(); method @Deprecated public String getIcbNum(); - method public String getIncomingCommunicationBarringNumber(); + method @Nullable public String getIncomingCommunicationBarringNumber(); method public int getProvisionStatus(); method public int getStatus(); method public void writeToParcel(android.os.Parcel, int); @@ -8864,7 +8857,7 @@ package android.telephony.ims { field public static final int SERVICE_PROVISIONING_UNKNOWN = -1; // 0xffffffff } - public static class ImsSsInfo.Builder { + public static final class ImsSsInfo.Builder { ctor public ImsSsInfo.Builder(int); method @NonNull public android.telephony.ims.ImsSsInfo build(); method @NonNull public android.telephony.ims.ImsSsInfo.Builder setClirInterrogationStatus(int); diff --git a/api/test-current.txt b/api/test-current.txt index a3b61552cc0e..c0701718306d 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -523,6 +523,7 @@ package android.app.role { method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback); method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String); method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>); + field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1 } public interface RoleManagerCallback { @@ -1011,7 +1012,7 @@ package android.media { 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 public Object prepareDrm(@NonNull android.media.DataSourceDesc, @NonNull java.util.UUID); + 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; @@ -3033,7 +3034,7 @@ package android.view.inspector { method public abstract String value(); } - @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface InspectableProperty { + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) public @interface InspectableProperty { method public abstract int attributeId() default android.content.res.Resources.ID_NULL; method public abstract android.view.inspector.InspectableProperty.EnumMap[] enumMapping() default {}; method public abstract android.view.inspector.InspectableProperty.FlagMap[] flagMapping() default {}; diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp index 012310cc277a..77a56e55045b 100644 --- a/cmds/incident_helper/src/ih_util.cpp +++ b/cmds/incident_helper/src/ih_util.cpp @@ -142,7 +142,7 @@ record_t parseRecordByColumns(const std::string& line, const std::vector<int>& i } if (lineSize - lastIndex > 0) { int beginning = lastIndex; - if (record.size() == indices.size()) { + if (record.size() == indices.size() && !record.empty()) { // We've already encountered all of the columns...put whatever is // left in the last column. record.pop_back(); diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp index 21ced9cb485c..5d525e6c7f3e 100644 --- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp +++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp @@ -65,8 +65,9 @@ CpuInfoParser::Parse(const int in, const int out) const if (line.empty()) continue; nline++; - - if (stripPrefix(&line, "Tasks:")) { + // The format changes from time to time in toybox/toys/posix/ps.c + // With -H, it prints Threads instead of Tasks (FLAG(H)?"Thread":"Task") + if (stripPrefix(&line, "Threads:")) { writeSuffixLine(&proto, CpuInfoProto::TASK_STATS, line, COMMA_DELIMITER, CpuInfoProto::TaskStats::_FIELD_COUNT, CpuInfoProto::TaskStats::_FIELD_NAMES, diff --git a/cmds/incident_helper/testdata/cpuinfo.txt b/cmds/incident_helper/testdata/cpuinfo.txt index ec4a83960698..aa3afc33ad6a 100644 --- a/cmds/incident_helper/testdata/cpuinfo.txt +++ b/cmds/incident_helper/testdata/cpuinfo.txt @@ -1,8 +1,8 @@ -Tasks: 2038 total, 1 running,2033 sleeping, 0 stopped, 0 zombie +Threads: 2038 total, 1 running,2033 sleeping, 0 stopped, 0 zombie -Mem: 3842668k total, 3761936k used, 80732k free, 220188k buffers + Mem: 3842668k total, 3761936k used, 80732k free, 220188k buffers -Swap: 524284k total, 25892k used, 498392k free, 1316952k cached + Swap: 524284k total, 25892k used, 498392k free, 1316952k cached 400%cpu 17%user 0%nice 43%sys 338%idle 0%iow 0%irq 1%sirq 0%host @@ -12,4 +12,4 @@ Swap: 524284k total, 25892k used, 498392k free, 1316952k cached 29438 29438 rootabcdefghij 20 0 57.9 R 14M 3.8M top test top 916 916 system 18 -2 1.4 S 4.6G 404M fg system_server system_server 28 28 root -2 0 1.4 S 0 0 bg rcuc/3 [rcuc/3] - 27 27 root RT 0 1.4 S 0 0 ta migration/3 [migration/3]
\ No newline at end of file + 27 27 root RT 0 1.4 S 0 0 ta migration/3 [migration/3] diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index da720021512d..7298da6f6835 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -219,6 +219,7 @@ cc_test { "tests/anomaly/AnomalyTracker_test.cpp", "tests/ConfigManager_test.cpp", "tests/external/puller_util_test.cpp", + "tests/external/IncidentReportArgs_test.cpp", "tests/external/StatsPuller_test.cpp", "tests/indexed_priority_queue_test.cpp", "tests/LogEntryMatcher_test.cpp", diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index a983b2705d14..5968fa8c2b06 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -1568,7 +1568,7 @@ message WatchdogRollbackOccurred { ROLLBACK_INITIATE = 1; ROLLBACK_SUCCESS = 2; ROLLBACK_FAILURE = 3; - ROLLBACK_ROOT_TRIGGERED = 4; + ROLLBACK_BOOT_TRIGGERED = 4; } optional RollbackType rollback_type = 1; diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 5c6d548ad13a..0e91f527083a 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -324,6 +324,12 @@ message IncidentdDetails { EXPLICIT = 1; } optional Destination dest = 2; + + // Package name of the incident report receiver. + optional string receiver_pkg = 3; + + // Class name of the incident report receiver. + optional string receiver_cls = 4; } message PerfettoDetails { diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp index 0ed2d75802da..7c2d2420528c 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp +++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp @@ -162,6 +162,10 @@ bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int } incidentReport.setDest(dest); + incidentReport.setReceiverPkg(config.receiver_pkg()); + + incidentReport.setReceiverCls(config.receiver_cls()); + sp<IIncidentManager> service = interface_cast<IIncidentManager>( defaultServiceManager()->getService(android::String16("incident"))); if (service == nullptr) { diff --git a/cmds/statsd/tests/external/IncidentReportArgs_test.cpp b/cmds/statsd/tests/external/IncidentReportArgs_test.cpp new file mode 100644 index 000000000000..c170b12dc242 --- /dev/null +++ b/cmds/statsd/tests/external/IncidentReportArgs_test.cpp @@ -0,0 +1,72 @@ +// 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. + +#include <android/os/IncidentReportArgs.h> + +#include <gtest/gtest.h> + +namespace android { +namespace os { +namespace statsd { + +TEST(IncidentReportArgsTest, testSerialization) { + IncidentReportArgs args; + args.setAll(0); + args.addSection(1000); + args.addSection(1001); + + vector<uint8_t> header1; + header1.push_back(0x1); + header1.push_back(0x2); + vector<uint8_t> header2; + header1.push_back(0x22); + header1.push_back(0x33); + + args.addHeader(header1); + args.addHeader(header2); + + args.setDest(1); + + args.setReceiverPkg("com.android.os"); + args.setReceiverCls("com.android.os.Receiver"); + + Parcel out; + status_t err = args.writeToParcel(&out); + EXPECT_EQ(NO_ERROR, err); + + out.setDataPosition(0); + + IncidentReportArgs args2; + err = args2.readFromParcel(&out); + EXPECT_EQ(NO_ERROR, err); + + EXPECT_EQ(0, args2.all()); + set<int> sections; + sections.insert(1000); + sections.insert(1001); + EXPECT_EQ(sections, args2.sections()); + EXPECT_EQ(1, args2.dest()); + + EXPECT_EQ(String16("com.android.os"), args2.receiverPkg()); + EXPECT_EQ(String16("com.android.os.Receiver"), args2.receiverCls()); + + vector<vector<uint8_t>> headers; + headers.push_back(header1); + headers.push_back(header2); + EXPECT_EQ(headers, args2.headers()); +} + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index 46a956cab1a8..9b0e6574e5c4 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -2935,7 +2935,6 @@ Lcom/android/internal/telephony/ServiceStateTracker;->isInHomeSidNid(II)Z Lcom/android/internal/telephony/ServiceStateTracker;->isInvalidOperatorNumeric(Ljava/lang/String;)Z Lcom/android/internal/telephony/ServiceStateTracker;->log(Ljava/lang/String;)V Lcom/android/internal/telephony/ServiceStateTracker;->loge(Ljava/lang/String;)V -Lcom/android/internal/telephony/ServiceStateTracker;->mAttachedRegistrants:Landroid/os/RegistrantList; Lcom/android/internal/telephony/ServiceStateTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface; Lcom/android/internal/telephony/ServiceStateTracker;->mCr:Landroid/content/ContentResolver; Lcom/android/internal/telephony/ServiceStateTracker;->mCurDataSpn:Ljava/lang/String; @@ -2947,7 +2946,6 @@ Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOffRegistrants Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOnRegistrants:Landroid/os/RegistrantList; Lcom/android/internal/telephony/ServiceStateTracker;->mDefaultRoamingIndicator:I Lcom/android/internal/telephony/ServiceStateTracker;->mDesiredPowerState:Z -Lcom/android/internal/telephony/ServiceStateTracker;->mDetachedRegistrants:Landroid/os/RegistrantList; Lcom/android/internal/telephony/ServiceStateTracker;->mDeviceShuttingDown:Z Lcom/android/internal/telephony/ServiceStateTracker;->mEmergencyOnly:Z Lcom/android/internal/telephony/ServiceStateTracker;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords; @@ -2975,7 +2973,6 @@ Lcom/android/internal/telephony/ServiceStateTracker;->mUiccApplcation:Lcom/andro Lcom/android/internal/telephony/ServiceStateTracker;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController; Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOffRegistrants:Landroid/os/RegistrantList; Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOnRegistrants:Landroid/os/RegistrantList; -Lcom/android/internal/telephony/ServiceStateTracker;->notifyDataRegStateRilRadioTechnologyChanged()V Lcom/android/internal/telephony/ServiceStateTracker;->notifySignalStrength()Z Lcom/android/internal/telephony/ServiceStateTracker;->pollState()V Lcom/android/internal/telephony/ServiceStateTracker;->reRegisterNetwork(Landroid/os/Message;)V diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 7d828d87e278..92db23b82891 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -276,6 +276,7 @@ public abstract class ActivityManagerInternal { public abstract boolean isActivityStartsLoggingEnabled(); /** Returns true if the background activity starts is enabled. */ public abstract boolean isBackgroundActivityStartsEnabled(); + public abstract boolean isPackageNameWhitelistedForBgActivityStarts(String packageName); public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing); /** Input dispatch timeout to a window, start the ANR process. */ diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b654258e6dcb..08239a1e7ed9 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -332,7 +332,6 @@ public final class ActivityThread extends ClientTransactionHandler { String[] mInstrumentedSplitAppDirs = null; String mInstrumentedLibDir = null; boolean mSystemThread = false; - boolean mJitEnabled = false; boolean mSomeActivitiesChanged = false; boolean mUpdatingSystemConfig = false; /* package */ boolean mHiddenApiWarningShown = false; @@ -1696,7 +1695,6 @@ public final class ActivityThread extends ClientTransactionHandler { public static final int SUICIDE = 130; @UnsupportedAppUsage public static final int REMOVE_PROVIDER = 131; - public static final int ENABLE_JIT = 132; public static final int DISPATCH_PACKAGE_BROADCAST = 133; @UnsupportedAppUsage public static final int SCHEDULE_CRASH = 134; @@ -1746,7 +1744,6 @@ public final class ActivityThread extends ClientTransactionHandler { case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT"; case SUICIDE: return "SUICIDE"; case REMOVE_PROVIDER: return "REMOVE_PROVIDER"; - case ENABLE_JIT: return "ENABLE_JIT"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case DUMP_HEAP: return "DUMP_HEAP"; @@ -1858,9 +1855,6 @@ public final class ActivityThread extends ClientTransactionHandler { completeRemoveProvider((ProviderRefCount)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; - case ENABLE_JIT: - ensureJitEnabled(); - break; case DISPATCH_PACKAGE_BROADCAST: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastPackage"); handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj); @@ -1996,7 +1990,6 @@ public final class ActivityThread extends ClientTransactionHandler { if (stopProfiling) { mProfiler.stopProfiling(); } - ensureJitEnabled(); return false; } } @@ -2330,13 +2323,6 @@ public final class ActivityThread extends ClientTransactionHandler { } } - void ensureJitEnabled() { - if (!mJitEnabled) { - mJitEnabled = true; - dalvik.system.VMRuntime.getRuntime().startJitCompilation(); - } - } - @UnsupportedAppUsage void scheduleGcIdler() { if (!mGcIdlerScheduled) { @@ -3782,7 +3768,6 @@ public final class ActivityThread extends ClientTransactionHandler { ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } - ensureJitEnabled(); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -3896,7 +3881,6 @@ public final class ActivityThread extends ClientTransactionHandler { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - ensureJitEnabled(); } catch (Exception e) { if (!mInstrumentation.onException(s, e)) { throw new RuntimeException( @@ -6177,9 +6161,6 @@ public final class ActivityThread extends ClientTransactionHandler { if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); - // For process that contains content providers, we want to - // ensure that the JIT is enabled "at some point". - mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); } } @@ -6812,12 +6793,6 @@ public final class ActivityThread extends ClientTransactionHandler { sCurrentActivityThread = this; mSystemThread = system; if (!system) { - ViewRootImpl.addFirstDrawHandler(new Runnable() { - @Override - public void run() { - ensureJitEnabled(); - } - }); android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId()); RuntimeInit.setApplicationObject(mAppThread.asBinder()); diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index 4a826d1faf90..010a900b9d96 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -16,18 +16,15 @@ package android.app; -import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; - +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.NotificationManager.InterruptionFilter; import android.content.ComponentName; -import android.content.Intent; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import android.service.notification.ZenPolicy; import android.service.notification.Condition; - -import com.android.internal.util.Preconditions; +import android.service.notification.ZenPolicy; import java.util.Objects; @@ -92,8 +89,9 @@ public final class AutomaticZenRule implements Parcelable { * action ({@link Condition#STATE_TRUE}). * @param enabled Whether the rule is enabled. */ - public AutomaticZenRule(String name, ComponentName owner, ComponentName configurationActivity, - Uri conditionId, ZenPolicy policy, int interruptionFilter, boolean enabled) { + public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner, + @Nullable ComponentName configurationActivity, @NonNull Uri conditionId, + @Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) { this.name = name; this.owner = owner; this.configurationActivity = configurationActivity; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index d593ad1fd0cd..efbd09844977 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3153,7 +3153,7 @@ public class DevicePolicyManager { * {@link #PASSWORD_QUALITY_ALPHANUMERIC} with {@link #setPasswordQuality}. * <p> * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the - * password is always treated as empty. + * password history length is always 0. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has @@ -3191,6 +3191,9 @@ public class DevicePolicyManager { * <p> * To disable password expiration, a value of 0 may be used for timeout. * <p> + * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password expiration is always disabled. + * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. @@ -3230,6 +3233,9 @@ public class DevicePolicyManager { * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve * restrictions on the parent profile. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password expiration is always disabled and this method always returns 0. + * * @param admin The name of the admin component to check, or {@code null} to aggregate all admins. * @return The timeout for the given admin or the minimum of all timeouts */ @@ -3255,6 +3261,9 @@ public class DevicePolicyManager { * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve * the password expiration for the parent profile. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password expiration is always disabled and this method always returns 0. + * * @param admin The name of the admin component to check, or {@code null} to aggregate all admins. * @return The password expiration time, in milliseconds since epoch. */ @@ -3279,6 +3288,9 @@ public class DevicePolicyManager { * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve * restrictions on the parent profile. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password history length is always 0. + * * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. * @return The length of the password history @@ -3306,7 +3318,7 @@ public class DevicePolicyManager { * Return the maximum password length that the device supports for a * particular password quality. * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the - * password is always empty. + * password is always empty and this method always returns 0. * @param quality The quality being interrogated. * @return Returns the maximum length that the user can enter. */ @@ -3362,7 +3374,7 @@ public class DevicePolicyManager { * #getParentProfileInstance}. * * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the - * password is always treated as empty. + * password is always empty and this method returns {@link #PASSWORD_COMPLEXITY_NONE}. * * @throws IllegalStateException if the user is not unlocked. * @throws SecurityException if the calling application does not have the permission @@ -3437,6 +3449,8 @@ public class DevicePolicyManager { * <p> * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} * to be able to call this method; if it has not, a security exception will be thrown. + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password is always empty and this method always returns 0. * * @return The number of times user has entered an incorrect password since the last correct * password entry. @@ -3503,6 +3517,8 @@ public class DevicePolicyManager { * This method can be called on the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set a value on the parent * profile. + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password is always empty and this method has no effect - i.e. the policy is not set. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param num The number of failed password attempts at which point the device or profile will @@ -3532,6 +3548,10 @@ public class DevicePolicyManager { * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve * the value for the parent profile. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * password is always empty and this method returns a default value (0) indicating that the + * policy is not set. + * * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. */ @@ -3619,6 +3639,8 @@ public class DevicePolicyManager { * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins * that are not device owner or profile owner. Once set, the password cannot be changed to null * or empty except by these admins.</em> + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, this + * methods does nothing. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call this method; if it has @@ -3669,6 +3691,8 @@ public class DevicePolicyManager { * will be stored on your server and who will need access to them. Tokens may be the subject of * legal access requests. * </em> + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the + * reset token is not set and this method returns false. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param token a secure token a least 32-byte long, which must be generated by a @@ -3693,6 +3717,10 @@ public class DevicePolicyManager { /** * Called by a profile or device owner to revoke the current password reset token. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, this + * method has no effect - the reset token should not have been set in the first place - and + * false is returned. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return true if the operation is successful, false otherwise. * @throws SecurityException if admin is not a device or profile owner. @@ -3713,6 +3741,9 @@ public class DevicePolicyManager { /** * Called by a profile or device owner to check if the current reset password token is active. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, + * false is always returned. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return true if the token is active, false otherwise. * @throws SecurityException if admin is not a device or profile owner. @@ -3748,6 +3779,8 @@ public class DevicePolicyManager { * <p> * Calling with a {@code null} or empty password will clear any existing PIN, pattern or * password if the current password constraints allow it. + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, + * calling this methods has no effect - the password is always empty - and false is returned. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param password The new password for the user. {@code null} or empty clears the password. @@ -3855,6 +3888,9 @@ public class DevicePolicyManager { * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, + * calling this methods has no effect - i.e. the timeout is not set. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param timeoutMs The new timeout in milliseconds, after which the user will have to unlock * with strong authentication method. A value of 0 means the admin is not participating @@ -3887,6 +3923,9 @@ public class DevicePolicyManager { * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve * restrictions on the parent profile. * + * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, + * 0 is returned to indicate that no timeout is configured. + * * @param admin The name of the admin component to check, or {@code null} to aggregate * across all participating admins. * @return The timeout in milliseconds or 0 if not configured for the provided admin. @@ -6617,6 +6656,9 @@ public class DevicePolicyManager { * This method can be called on the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set the configuration for * the parent profile. + * <p> + * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, calling + * this method has no effect - no trust agent configuration will be set. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param target Component name of the agent to be configured. @@ -6646,6 +6688,9 @@ public class DevicePolicyManager { * This method can be called on the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to retrieve the configuration set * on the parent profile. + * <p> + * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, null is + * always returned. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. If null, * this function returns a list of configurations for all admins that declare diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.java b/core/java/android/app/contentsuggestions/ClassificationsRequest.java index 1b50015ffc71..2051a55e1c2f 100644 --- a/core/java/android/app/contentsuggestions/ClassificationsRequest.java +++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.java @@ -54,10 +54,10 @@ public final class ClassificationsRequest implements Parcelable { } /** - * Return the request extras or {@code null} if there are none. + * Return the request extras, can be an empty bundle. */ - public @Nullable Bundle getExtras() { - return mExtras; + public @NonNull Bundle getExtras() { + return mExtras == null ? new Bundle() : mExtras; } @Override @@ -103,7 +103,7 @@ public final class ClassificationsRequest implements Parcelable { /** * Sets the request extras. */ - public Builder setExtras(@NonNull Bundle extras) { + public @NonNull Builder setExtras(@NonNull Bundle extras) { mExtras = extras; return this; } @@ -111,7 +111,7 @@ public final class ClassificationsRequest implements Parcelable { /** * Builds a new request instance. */ - public ClassificationsRequest build() { + public @NonNull ClassificationsRequest build() { return new ClassificationsRequest(mSelections, mExtras); } } diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.java b/core/java/android/app/contentsuggestions/SelectionsRequest.java index 257f98d5d7d6..84f33b552893 100644 --- a/core/java/android/app/contentsuggestions/SelectionsRequest.java +++ b/core/java/android/app/contentsuggestions/SelectionsRequest.java @@ -63,10 +63,10 @@ public final class SelectionsRequest implements Parcelable { } /** - * Return the request extras or {@code null} if there aren't any. + * Return the request extras, may be an empty bundle if there aren't any. */ - public @Nullable Bundle getExtras() { - return mExtras; + public @NonNull Bundle getExtras() { + return mExtras == null ? new Bundle() : mExtras; } @Override @@ -118,7 +118,7 @@ public final class SelectionsRequest implements Parcelable { /** * Sets the request extras. */ - public Builder setExtras(@NonNull Bundle extras) { + public @NonNull Builder setExtras(@NonNull Bundle extras) { mExtras = extras; return this; } @@ -126,7 +126,7 @@ public final class SelectionsRequest implements Parcelable { /** * Sets the request interest point. */ - public Builder setInterestPoint(@NonNull Point interestPoint) { + public @NonNull Builder setInterestPoint(@NonNull Point interestPoint) { mInterestPoint = interestPoint; return this; } @@ -134,7 +134,7 @@ public final class SelectionsRequest implements Parcelable { /** * Builds a new request instance. */ - public SelectionsRequest build() { + public @NonNull SelectionsRequest build() { return new SelectionsRequest(mTaskId, mInterestPoint, mExtras); } } diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java index c665cb238028..f91d8780084f 100644 --- a/core/java/android/app/role/RoleManager.java +++ b/core/java/android/app/role/RoleManager.java @@ -187,6 +187,7 @@ public final class RoleManager { * @hide */ @SystemApi + @TestApi public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; /** diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index b72ec39a5543..62b24e9995e8 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -60,7 +60,7 @@ interface IUsageStatsManager { in PendingIntent sessionEndCallbackIntent, String callingPackage); void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage); void registerAppUsageLimitObserver(int observerId, in String[] packages, long timeLimitMs, - in PendingIntent callback, String callingPackage); + long timeRemainingMs, in PendingIntent callback, String callingPackage); void unregisterAppUsageLimitObserver(int observerId, String callingPackage); void reportUsageStart(in IBinder activity, String token, String callingPackage); void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs, diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index d34e6d3836b8..cee6b87fd3f1 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -35,6 +35,7 @@ import android.util.ArrayMap; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -738,6 +739,23 @@ public final class UsageStatsManager { } /** + * @deprecated use + * {@link #registerAppUsageLimitObserver(int, String[], Duration, Duration, PendingIntent)}. + * + * @removed + * @hide + */ + @Deprecated + @UnsupportedAppUsage + // STOPSHIP b/126917290: remove this method once ag/6591106 is merged and it's not being used. + public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities, + long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) { + final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit)); + registerAppUsageLimitObserver(observerId, observedEntities, + timeLimitDuration, timeLimitDuration, callbackIntent); + } + + /** * Register a usage limit observer that receives a callback on the provided intent when the * sum of usages of apps and tokens in the provided {@code observedEntities} array exceeds the * {@code timeLimit} specified. The structure of a token is a {@link String} with the reporting @@ -759,19 +777,21 @@ public final class UsageStatsManager { * @see android.content.pm.LauncherApps#getAppUsageLimit * * @param observerId A unique id associated with the group of apps to be monitored. There can - * be multiple groups with common packages and different time limits. + * be multiple groups with common packages and different time limits. * @param observedEntities The list of packages and token to observe for usage time. Cannot be * null and must include at least one package or token. * @param timeLimit The total time the set of apps can be in the foreground before the - * callbackIntent is delivered. Must be at least one minute. Note: a limit of - * 0 can be set to indicate that the user has already exhausted the limit for - * a group, in which case, the given {@code callbackIntent} will be ignored. - * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null. + * {@code callbackIntent} is delivered. Must be at least one minute. + * @param timeRemaining The remaining time the set of apps can be in the foreground before the + * {@code callbackIntent} is delivered. Must be greater than + * {@code timeLimit}. Note: a limit of 0 can be set to indicate that the + * user has already exhausted the limit for a group, in which case, + * the given {@code callbackIntent} will be ignored. * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is * exceeded by the group of apps. The delivered Intent will also contain * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is - * being registered with a {@code timeLimit} of 0. + * being registered with a {@code timeRemaining} of 0. * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE * permissions. * @hide @@ -781,10 +801,12 @@ public final class UsageStatsManager { android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities, - long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) { + @NonNull Duration timeLimit, @NonNull Duration timeRemaining, + @Nullable PendingIntent callbackIntent) { try { mService.registerAppUsageLimitObserver(observerId, observedEntities, - timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName()); + timeLimit.toMillis(), timeRemaining.toMillis(), callbackIntent, + mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java index 2142cf3ebda3..3d1ddc3ca77b 100644 --- a/core/java/android/content/LocusId.java +++ b/core/java/android/content/LocusId.java @@ -16,7 +16,6 @@ package android.content; import android.annotation.NonNull; -import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -34,28 +33,28 @@ import java.io.PrintWriter; // TODO(b/123577059): make sure this is well documented and understandable public final class LocusId implements Parcelable { - private final Uri mUri; + private final String mId; /** * Default constructor. */ - public LocusId(@NonNull Uri uri) { - mUri = Preconditions.checkNotNull(uri); + public LocusId(@NonNull String id) { + mId = Preconditions.checkNotNull(id); } /** - * Gets the {@code uri} associated with the locus. + * Gets the {@code id} associated with the locus. */ @NonNull - public Uri getUri() { - return mUri; + public String getId() { + return mId; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((mUri == null) ? 0 : mUri.hashCode()); + result = prime * result + ((mId == null) ? 0 : mId.hashCode()); return result; } @@ -65,26 +64,27 @@ public final class LocusId implements Parcelable { if (obj == null) return false; if (getClass() != obj.getClass()) return false; final LocusId other = (LocusId) obj; - if (mUri == null) { - if (other.mUri != null) return false; + if (mId == null) { + if (other.mId != null) return false; } else { - if (!mUri.equals(other.mUri)) return false; + if (!mId.equals(other.mId)) return false; } return true; } @Override public String toString() { - return "LocusId[uri=" + getSanitizedUri() + "]"; + return "LocusId[" + getSanitizedId() + "]"; } /** @hide */ public void dump(@NonNull PrintWriter pw) { - pw.print("uri:"); pw.println(getSanitizedUri()); + pw.print("id:"); pw.println(getSanitizedId()); } - private String getSanitizedUri() { - final int size = mUri.toString().length(); + @NonNull + private String getSanitizedId() { + final int size = mId.length(); return size + "_chars"; } @@ -94,8 +94,8 @@ public final class LocusId implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mUri, flags); + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mId); } public static final @android.annotation.NonNull Parcelable.Creator<LocusId> CREATOR = @@ -103,9 +103,8 @@ public final class LocusId implements Parcelable { @NonNull @Override - public LocusId createFromParcel(Parcel source) { - final Uri uri = source.readParcelable(null); - return new LocusId(uri); + public LocusId createFromParcel(Parcel parcel) { + return new LocusId(parcel.readString()); } @NonNull diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 38ea43e0219b..0cc5f3931487 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -792,7 +792,7 @@ public class LauncherApps { * * @return an {@link AppUsageLimit} object describing the app time limit containing * the given package with the smallest time remaining, or {@code null} if none exist. - * @throws SecurityException when the caller is not the active launcher. + * @throws SecurityException when the caller is not the recents app. */ @Nullable public LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String packageName, diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 0304f19cc5b4..b20cce9b7e3e 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1343,6 +1343,7 @@ public class PackageInstaller { */ public boolean areHiddenOptionsSet() { return (installFlags & (PackageManager.INSTALL_ALLOW_DOWNGRADE + | PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE | PackageManager.INSTALL_DONT_KILL_APP | PackageManager.INSTALL_INSTANT_APP | PackageManager.INSTALL_FULL_APP diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a5464c2137af..c133fba031f2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -721,6 +721,7 @@ public abstract class PackageManager { INSTALL_VIRTUAL_PRELOAD, INSTALL_APEX, INSTALL_ENABLE_ROLLBACK, + INSTALL_RESPECT_ALLOW_DOWNGRADE, }) @Retention(RetentionPolicy.SOURCE) public @interface InstallFlags {} @@ -865,6 +866,15 @@ public abstract class PackageManager { */ public static final int INSTALL_DISABLE_VERIFICATION = 0x00080000; + /** + * Flag parameter for {@link #installPackage} to indicate that + * {@link #INSTALL_ALLOW_DOWNGRADE} should be respected. + * + * @hide + */ + // TODO(b/127322579): rename + public static final int INSTALL_RESPECT_ALLOW_DOWNGRADE = 0x00100000; + /** @hide */ @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = { DONT_KILL_APP diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index a25bbdb8bf89..9da8e4eb0a6d 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -85,7 +85,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * * @hide */ - public Key(String name, String fallbackName, Class<T> type) { + @UnsupportedAppUsage + public Key(@NonNull String name, @NonNull String fallbackName, @NonNull Class<T> type) { mKey = new CameraMetadataNative.Key<T>(name, fallbackName, type); } diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 536c2e13389b..234014327150 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -678,6 +678,31 @@ public final class CameraManager { public void onCameraUnavailable(@NonNull String cameraId) { // default empty implementation } + + /** + * Notify registered clients about a change in the camera access priorities. + * + * <p>Notification that camera access priorities have changed and the camera may + * now be openable. An application that was previously denied camera access due to + * a higher-priority user already using the camera, or that was disconnected from an + * active camera session due to a higher-priority user trying to open the camera, + * should try to open the camera again if it still wants to use it. Note that + * multiple applications may receive this callback at the same time, and only one of + * them will succeed in opening the camera in practice, depending on exact access + * priority levels and timing. This method is useful in cases where multiple + * applications may be in the resumed state at the same time, and the user switches + * focus between them, or if the current camera-using application moves between + * full-screen and Picture-in-Picture (PiP) states. In such cases, the camera + * available/unavailable callbacks will not be invoked, but another application may + * now have higher priority for camera access than the current camera-using + * application.</p> + * + * <p>The default implementation of this method does nothing.</p> + * + */ + public void onCameraAccessPrioritiesChanged() { + // default empty implementation + } } /** @@ -1098,6 +1123,22 @@ public final class CameraManager { } } + private void postSingleAccessPriorityChangeUpdate(final AvailabilityCallback callback, + final Executor executor) { + final long ident = Binder.clearCallingIdentity(); + try { + executor.execute( + new Runnable() { + @Override + public void run() { + callback.onCameraAccessPrioritiesChanged(); + } + }); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor, final String id, final int status) { if (isAvailable(status)) { @@ -1347,6 +1388,19 @@ public final class CameraManager { } } + @Override + public void onCameraAccessPrioritiesChanged() { + synchronized (mLock) { + final int callbackCount = mCallbackMap.size(); + for (int i = 0; i < callbackCount; i++) { + Executor executor = mCallbackMap.valueAt(i); + final AvailabilityCallback callback = mCallbackMap.keyAt(i); + + postSingleAccessPriorityChangeUpdate(callback, executor); + } + } + } + /** * Try to connect to camera service after some delay if any client registered camera * availability callback or torch status callback. diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 53d4dd3d36ee..bb0987dd0798 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -89,7 +89,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * * @hide */ - public Key(String name, String fallbackName, Class<T> type) { + @UnsupportedAppUsage + public Key(@NonNull String name, @NonNull String fallbackName, @NonNull Class<T> type) { mKey = new CameraMetadataNative.Key<T>(name, fallbackName, type); } @@ -4251,6 +4252,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * @see CaptureResult#SENSOR_TIMESTAMP * @hide */ + @UnsupportedAppUsage public static final Key<long[]> STATISTICS_OIS_TIMESTAMPS = new Key<long[]>("android.statistics.oisTimestamps", long[].class); @@ -4270,6 +4272,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * @hide */ + @UnsupportedAppUsage public static final Key<float[]> STATISTICS_OIS_X_SHIFTS = new Key<float[]>("android.statistics.oisXShifts", float[].class); @@ -4289,6 +4292,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * @hide */ + @UnsupportedAppUsage public static final Key<float[]> STATISTICS_OIS_Y_SHIFTS = new Key<float[]>("android.statistics.oisYShifts", float[].class); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index a17ebcbedd1a..eb0fe33df03a 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -143,6 +143,7 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_NOT_CONGESTED, NET_CAPABILITY_NOT_SUSPENDED, NET_CAPABILITY_OEM_PAID, + NET_CAPABILITY_MCX }) public @interface NetCapability { } @@ -297,8 +298,14 @@ public final class NetworkCapabilities implements Parcelable { @SystemApi public static final int NET_CAPABILITY_OEM_PAID = 22; + /** + * Indicates this is a network that has the ability to reach a carrier's Mission Critical + * servers. + */ + public static final int NET_CAPABILITY_MCX = 23; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_OEM_PAID; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_MCX; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -346,7 +353,8 @@ public final class NetworkCapabilities implements Parcelable { (1 << NET_CAPABILITY_IA) | (1 << NET_CAPABILITY_IMS) | (1 << NET_CAPABILITY_RCS) | - (1 << NET_CAPABILITY_XCAP); + (1 << NET_CAPABILITY_XCAP) | + (1 << NET_CAPABILITY_MCX); /** * Capabilities that force network to be restricted. @@ -1614,6 +1622,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED"; case NET_CAPABILITY_OEM_PAID: return "OEM_PAID"; + case NET_CAPABILITY_MCX: return "MCX"; default: return Integer.toString(capability); } } diff --git a/core/java/android/os/IncidentReportArgs.java b/core/java/android/os/IncidentReportArgs.java index 1bdfd945c5b0..a1f2430f4ee3 100644 --- a/core/java/android/os/IncidentReportArgs.java +++ b/core/java/android/os/IncidentReportArgs.java @@ -36,6 +36,8 @@ public final class IncidentReportArgs implements Parcelable { private final ArrayList<byte[]> mHeaders = new ArrayList<byte[]>(); private boolean mAll; private int mPrivacyPolicy; + private String mReceiverPkg; + private String mReceiverCls; /** * Construct an incident report args with no fields. @@ -73,6 +75,10 @@ public final class IncidentReportArgs implements Parcelable { } out.writeInt(mPrivacyPolicy); + + out.writeString(mReceiverPkg); + + out.writeString(mReceiverCls); } public void readFromParcel(Parcel in) { @@ -91,6 +97,10 @@ public final class IncidentReportArgs implements Parcelable { } mPrivacyPolicy = in.readInt(); + + mReceiverPkg = in.readString(); + + mReceiverCls = in.readString(); } public static final @android.annotation.NonNull Parcelable.Creator<IncidentReportArgs> CREATOR @@ -126,6 +136,8 @@ public final class IncidentReportArgs implements Parcelable { sb.append(mHeaders.size()); sb.append(" headers), "); sb.append("privacy: ").append(mPrivacyPolicy); + sb.append("receiver pkg: ").append(mReceiverPkg); + sb.append("receiver cls: ").append(mReceiverCls); return sb.toString(); } diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl index cb2517e956df..76e911ddaf5a 100644 --- a/core/java/android/permission/IPermissionController.aidl +++ b/core/java/android/permission/IPermissionController.aidl @@ -40,6 +40,7 @@ oneway interface IPermissionController { void getPermissionUsages(boolean countSystem, long numMillis, in RemoteCallback callback); void isApplicationQualifiedForRole(String roleName, String packageName, in RemoteCallback callback); + void isRoleVisible(String roleName, in RemoteCallback callback); void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName, String packageName, String permission, int grantState, in RemoteCallback callback); } diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index 9d58064ab6d0..5695e42bef8e 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -476,6 +476,26 @@ public final class PermissionControllerManager { } /** + * Check whether a role should be visible to user. + * + * @param roleName name of the role to check for + * @param executor Executor on which to invoke the callback + * @param callback Callback to receive the result + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) + public void isRoleVisible(@NonNull String roleName, + @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { + checkStringNotEmpty(roleName); + checkNotNull(executor); + checkNotNull(callback); + + mRemoteService.scheduleRequest(new PendingIsRoleVisibleRequest(mRemoteService, roleName, + executor, callback)); + } + + /** * A connection to the remote service */ static final class RemoteService extends @@ -1222,4 +1242,55 @@ public final class PermissionControllerManager { } } } + + /** + * Request for {@link #isRoleVisible}. + */ + private static final class PendingIsRoleVisibleRequest extends + AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { + + private final @NonNull String mRoleName; + private final @NonNull Consumer<Boolean> mCallback; + + private final @NonNull RemoteCallback mRemoteCallback; + + private PendingIsRoleVisibleRequest(@NonNull RemoteService service, + @NonNull String roleName, @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> callback) { + super(service); + + mRoleName = roleName; + mCallback = callback; + + mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { + long token = Binder.clearCallingIdentity(); + try { + boolean visible; + if (result != null) { + visible = result.getBoolean(KEY_RESULT); + } else { + visible = false; + } + callback.accept(visible); + } finally { + Binder.restoreCallingIdentity(token); + finish(); + } + }), null); + } + + @Override + protected void onTimeout(RemoteService remoteService) { + mCallback.accept(false); + } + + @Override + public void run() { + try { + getService().getServiceInterface().isRoleVisible(mRoleName, mRemoteCallback); + } catch (RemoteException e) { + Log.e(TAG, "Error checking whether role should be visible", e); + } + } + } } diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index ee03689f211d..d375c10e6d4c 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -179,12 +179,21 @@ public abstract class PermissionControllerService extends Service { * @param roleName name of the role to check for * @param packageName package name of the application to check for * - * @return whether the application is qualified for the role. + * @return whether the application is qualified for the role */ public abstract boolean onIsApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName); /** + * Check whether a role should be visible to user. + * + * @param roleName name of the role to check for + * + * @return whether the role should be visible to user + */ + public abstract boolean onIsRoleVisible(@NonNull String roleName); + + /** * Set the runtime permission state from a device admin. * * @param callerPackageName The package name of the admin requesting the change @@ -344,6 +353,18 @@ public abstract class PermissionControllerService extends Service { } @Override + public void isRoleVisible(String roleName, RemoteCallback callback) { + checkStringNotEmpty(roleName); + checkNotNull(callback, "callback"); + + enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null); + + mHandler.sendMessage(obtainMessage( + PermissionControllerService::isRoleVisible, + PermissionControllerService.this, roleName, callback)); + } + + @Override public void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName, String packageName, String permission, int grantState, RemoteCallback callback) { @@ -445,6 +466,13 @@ public abstract class PermissionControllerService extends Service { callback.sendResult(result); } + private void isRoleVisible(@NonNull String roleName, @NonNull RemoteCallback callback) { + boolean visible = onIsRoleVisible(roleName); + Bundle result = new Bundle(); + result.putBoolean(PermissionControllerManager.KEY_RESULT, visible); + callback.sendResult(result); + } + private void setRuntimePermissionGrantStateByDeviceAdmin(@NonNull String callerPackageName, @NonNull String packageName, @NonNull String permission, @PermissionGrantState int grantState, @NonNull RemoteCallback callback) { diff --git a/core/java/android/permission/RuntimePermissionPresentationInfo.java b/core/java/android/permission/RuntimePermissionPresentationInfo.java index d66789fa1ac2..4fce14cef3f0 100644 --- a/core/java/android/permission/RuntimePermissionPresentationInfo.java +++ b/core/java/android/permission/RuntimePermissionPresentationInfo.java @@ -21,6 +21,8 @@ import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.Preconditions; + /** * This class contains information about how a runtime permission * is to be presented in the UI. A single runtime permission @@ -35,7 +37,7 @@ public final class RuntimePermissionPresentationInfo implements Parcelable { private static final int FLAG_GRANTED = 1 << 0; private static final int FLAG_STANDARD = 1 << 1; - private final CharSequence mLabel; + private final @NonNull CharSequence mLabel; private final int mFlags; /** @@ -45,8 +47,10 @@ public final class RuntimePermissionPresentationInfo implements Parcelable { * @param granted Whether the permission is granted. * @param standard Whether this is a platform-defined permission. */ - public RuntimePermissionPresentationInfo(CharSequence label, + public RuntimePermissionPresentationInfo(@NonNull CharSequence label, boolean granted, boolean standard) { + Preconditions.checkNotNull(label); + mLabel = label; int flags = 0; if (granted) { @@ -58,11 +62,6 @@ public final class RuntimePermissionPresentationInfo implements Parcelable { mFlags = flags; } - private RuntimePermissionPresentationInfo(Parcel parcel) { - mLabel = parcel.readCharSequence(); - mFlags = parcel.readInt(); - } - /** * @return Whether the permission is granted. */ @@ -97,10 +96,14 @@ public final class RuntimePermissionPresentationInfo implements Parcelable { parcel.writeInt(mFlags); } - public static final @android.annotation.NonNull Creator<RuntimePermissionPresentationInfo> CREATOR = + public static final @NonNull Creator<RuntimePermissionPresentationInfo> CREATOR = new Creator<RuntimePermissionPresentationInfo>() { public RuntimePermissionPresentationInfo createFromParcel(Parcel source) { - return new RuntimePermissionPresentationInfo(source); + CharSequence label = source.readCharSequence(); + int flags = source.readInt(); + + return new RuntimePermissionPresentationInfo(label, (flags & FLAG_GRANTED) != 0, + (flags & FLAG_STANDARD) != 0); } public RuntimePermissionPresentationInfo[] newArray(int size) { diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 2cd3c48b0eb8..5d4539cb62af 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -64,12 +64,14 @@ public final class DeviceConfig { public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; /** - * Namespace for all Game Driver features. + * Namespace for all activity manager related features that are used at the native level. + * These features are applied at reboot. * * @hide */ @SystemApi - public static final String NAMESPACE_GAME_DRIVER = "game_driver"; + public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = + "activity_manager_native_boot"; /** * Namespace for autofill feature that provides suggestions across all apps when @@ -92,6 +94,14 @@ public final class DeviceConfig { public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; /** + * Namespace for all Game Driver features. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_GAME_DRIVER = "game_driver"; + + /** * Namespace for all input-related features that are used at the native level. * These features are applied at reboot. * @@ -101,6 +111,14 @@ public final class DeviceConfig { public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot"; /** + * Namespace for all media native related features. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; + + /** * Namespace for all netd related features. * * @hide @@ -109,6 +127,15 @@ public final class DeviceConfig { public static final String NAMESPACE_NETD_NATIVE = "netd_native"; /** + * Namespace for all runtime native boot related features. Boot in this case refers to the + * fact that the properties only take affect after rebooting the device. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot"; + + /** * Namespace for System UI related features. * * @hide @@ -174,40 +201,6 @@ public final class DeviceConfig { } /** - * Namespace for all runtime native boot related features. Boot in this case refers to the - * fact that the properties only take affect after rebooting the device. - * - * @hide - */ - @SystemApi - public interface RuntimeNativeBoot { - String NAMESPACE = "runtime_native_boot"; - } - - /** - * Namespace for all media native related features. - * - * @hide - */ - @SystemApi - public interface MediaNative { - /** The flag namespace for media native features. */ - String NAMESPACE = "media_native"; - } - - /** - * Namespace for all activity manager related features that are used at the native level. - * These features are applied at reboot. - * - * @hide - */ - @SystemApi - public interface ActivityManagerNativeBoot { - String NAMESPACE = "activity_manager_native_boot"; - String OFFLOAD_QUEUE_ENABLED = "offload_queue_enabled"; - } - - /** * Namespace for attention-based features provided by on-device machine intelligence. * * @hide diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index a34ac706c406..917b5c2615db 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -146,6 +146,8 @@ public final class MediaStore { public static final String RETRANSLATE_CALL = "update_titles"; /** {@hide} */ + public static final String GET_VERSION_CALL = "get_version"; + /** {@hide} */ public static final String GET_DOCUMENT_URI_CALL = "get_document_uri"; /** {@hide} */ public static final String GET_MEDIA_URI_CALL = "get_media_uri"; @@ -3318,21 +3320,41 @@ public final class MediaStore { public static final String MEDIA_IGNORE_FILENAME = ".nomedia"; /** - * Get the media provider's version. - * Applications that import data from the media provider into their own caches - * can use this to detect that the media provider changed, and reimport data - * as needed. No other assumptions should be made about the meaning of the version. - * @param context Context to use for performing the query. - * @return A version string, or null if the version could not be determined. + * Return an opaque version string describing the {@link MediaStore} state. + * <p> + * Applications that import data from {@link MediaStore} into their own + * caches can use this to detect that {@link MediaStore} has undergone + * substantial changes, and that data should be rescanned. + * <p> + * No other assumptions should be made about the meaning of the version. + * <p> + * This method returns the version for {@link MediaStore#VOLUME_EXTERNAL}; + * to obtain a version for a different volume, use + * {@link #getVersion(Context, String)}. */ - public static String getVersion(Context context) { - final Uri uri = AUTHORITY_URI.buildUpon().appendPath("none").appendPath("version").build(); - try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) { - if (c.moveToFirst()) { - return c.getString(0); - } + public static @NonNull String getVersion(@NonNull Context context) { + return getVersion(context, VOLUME_EXTERNAL); + } + + /** + * Return an opaque version string describing the {@link MediaStore} state. + * <p> + * Applications that import data from {@link MediaStore} into their own + * caches can use this to detect that {@link MediaStore} has undergone + * substantial changes, and that data should be rescanned. + * <p> + * No other assumptions should be made about the meaning of the version. + */ + public static @NonNull String getVersion(@NonNull Context context, @NonNull String volumeName) { + final ContentResolver resolver = context.getContentResolver(); + try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) { + final Bundle in = new Bundle(); + in.putString(Intent.EXTRA_TEXT, volumeName); + final Bundle out = client.call(GET_VERSION_CALL, null, in); + return out.getString(Intent.EXTRA_TEXT); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); } - return null; } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 368fc2a12c92..027525bd56a5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3321,6 +3321,17 @@ public final class Settings { ColorDisplayManager.COLOR_MODE_AUTOMATIC); /** + * The user selected peak refresh rate in frames per second. + * + * If this isn't set, the system falls back to a device specific default. + * @hide + */ + public static final String PEAK_REFRESH_RATE = "peak_refresh_rate"; + + private static final Validator PEAK_REFRESH_RATE_VALIDATOR = + new SettingsValidators.InclusiveFloatRangeValidator(24f, Float.MAX_VALUE); + + /** * The amount of time in milliseconds before the device goes to sleep or begins * to dream after a period of inactivity. This value is also known as the * user activity timeout period since the screen isn't necessarily turned off @@ -11442,6 +11453,15 @@ public final class Settings { "background_activity_starts_enabled"; /** + * The packages temporarily whitelisted to be able so start activities from background. + * The list of packages is {@code ":"} colon delimited. + * + * @hide + */ + public static final String BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST = + "background_activity_starts_package_names_whitelist"; + + /** * @hide * @see com.android.server.appbinding.AppBindingConstants */ diff --git a/core/java/android/service/carrier/ApnService.java b/core/java/android/service/carrier/ApnService.java index d53eb37ca786..57e4b1b40748 100644 --- a/core/java/android/service/carrier/ApnService.java +++ b/core/java/android/service/carrier/ApnService.java @@ -16,6 +16,8 @@ package android.service.carrier; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.WorkerThread; import android.app.Service; @@ -60,7 +62,8 @@ public abstract class ApnService extends Service { }; @Override - public IBinder onBind(Intent intent) { + @NonNull + public IBinder onBind(@Nullable Intent intent) { return mBinder; } @@ -73,5 +76,6 @@ public abstract class ApnService extends Service { * subId. */ @WorkerThread + @NonNull public abstract List<ContentValues> onRestoreApns(int subId); } diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java index 40333bf7709e..28143003fcc4 100644 --- a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java +++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java @@ -52,6 +52,10 @@ public abstract class ContentSuggestionsService extends Service { /** * The action for the intent used to define the content suggestions service. + * + * <p>To be supported, the service must also require the + * * {@link android.Manifest.permission#BIND_CONTENT_SUGGESTIONS_SERVICE} permission so + * * that other applications can not abuse it. */ public static final String SERVICE_INTERFACE = "android.service.contentsuggestions.ContentSuggestionsService"; diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java index 74e6c6e29e00..7ef40cd20895 100644 --- a/core/java/android/service/notification/ZenPolicy.java +++ b/core/java/android/service/notification/ZenPolicy.java @@ -17,6 +17,7 @@ package android.service.notification; import android.annotation.IntDef; +import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationChannel; import android.os.Parcel; @@ -378,14 +379,14 @@ public final class ZenPolicy implements Parcelable { /** * Builds the current ZenPolicy. */ - public ZenPolicy build() { + public @NonNull ZenPolicy build() { return mZenPolicy.copy(); } /** * Allows all notifications to bypass DND and unmutes all streams. */ - public Builder allowAllSounds() { + public @NonNull Builder allowAllSounds() { for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) { mZenPolicy.mPriorityCategories.set(i, STATE_ALLOW); } @@ -401,7 +402,7 @@ public final class ZenPolicy implements Parcelable { * {@link NotificationChannel#canBypassDnd can bypass DND}. If no channels can bypass DND, * the ringer stream is also muted. */ - public Builder disallowAllSounds() { + public @NonNull Builder disallowAllSounds() { for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) { mZenPolicy.mPriorityCategories.set(i, STATE_DISALLOW); } @@ -413,7 +414,7 @@ public final class ZenPolicy implements Parcelable { /** * Allows notifications intercepted by DND to show on all surfaces when DND is active. */ - public Builder showAllVisualEffects() { + public @NonNull Builder showAllVisualEffects() { for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) { mZenPolicy.mVisualEffects.set(i, STATE_ALLOW); } @@ -423,7 +424,7 @@ public final class ZenPolicy implements Parcelable { /** * Disallows notifications intercepted by DND from showing when DND is active. */ - public Builder hideAllVisualEffects() { + public @NonNull Builder hideAllVisualEffects() { for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) { mZenPolicy.mVisualEffects.set(i, STATE_DISALLOW); } @@ -435,7 +436,7 @@ public final class ZenPolicy implements Parcelable { * unset categories will default to the current applied policy. * @hide */ - public Builder unsetPriorityCategory(@PriorityCategory int category) { + public @NonNull Builder unsetPriorityCategory(@PriorityCategory int category) { mZenPolicy.mPriorityCategories.set(category, STATE_UNSET); if (category == PRIORITY_CATEGORY_MESSAGES) { @@ -452,7 +453,7 @@ public final class ZenPolicy implements Parcelable { * unset effects will default to the current applied policy. * @hide */ - public Builder unsetVisualEffect(@VisualEffect int effect) { + public @NonNull Builder unsetVisualEffect(@VisualEffect int effect) { mZenPolicy.mVisualEffects.set(effect, STATE_UNSET); return this; } @@ -461,7 +462,7 @@ public final class ZenPolicy implements Parcelable { * Whether to allow notifications with category {@link Notification#CATEGORY_REMINDER} * to play sounds and visually appear or to intercept them when DND is active. */ - public Builder allowReminders(boolean allow) { + public @NonNull Builder allowReminders(boolean allow) { mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REMINDERS, allow ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -471,7 +472,7 @@ public final class ZenPolicy implements Parcelable { * Whether to allow notifications with category {@link Notification#CATEGORY_EVENT} * to play sounds and visually appear or to intercept them when DND is active. */ - public Builder allowEvents(boolean allow) { + public @NonNull Builder allowEvents(boolean allow) { mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_EVENTS, allow ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -483,7 +484,7 @@ public final class ZenPolicy implements Parcelable { * them when DND is active. * @param audienceType message senders that are allowed to bypass DND */ - public Builder allowMessages(@PeopleType int audienceType) { + public @NonNull Builder allowMessages(@PeopleType int audienceType) { if (audienceType == STATE_UNSET) { return unsetPriorityCategory(PRIORITY_CATEGORY_MESSAGES); } @@ -507,7 +508,7 @@ public final class ZenPolicy implements Parcelable { * them when DND is active. * @param audienceType callers that are allowed to bypass DND */ - public Builder allowCalls(@PeopleType int audienceType) { + public @NonNull Builder allowCalls(@PeopleType int audienceType) { if (audienceType == STATE_UNSET) { return unsetPriorityCategory(PRIORITY_CATEGORY_CALLS); } @@ -530,7 +531,7 @@ public final class ZenPolicy implements Parcelable { * {@link Notification#CATEGORY_CALL} that have recently called * to play sounds and visually appear. */ - public Builder allowRepeatCallers(boolean allow) { + public @NonNull Builder allowRepeatCallers(boolean allow) { mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REPEAT_CALLERS, allow ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -542,7 +543,7 @@ public final class ZenPolicy implements Parcelable { * to play sounds and visually appear or to intercept them when DND is active. * Disallowing alarms will mute the alarm stream when DND is active. */ - public Builder allowAlarms(boolean allow) { + public @NonNull Builder allowAlarms(boolean allow) { mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_ALARMS, allow ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -553,7 +554,7 @@ public final class ZenPolicy implements Parcelable { * appear or to intercept them when DND is active. * Disallowing media will mute the media stream when DND is active. */ - public Builder allowMedia(boolean allow) { + public @NonNull Builder allowMedia(boolean allow) { mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MEDIA, allow ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -563,7 +564,7 @@ public final class ZenPolicy implements Parcelable { * Whether to allow system sounds to play when DND is active. * Disallowing system sounds will mute the system stream when DND is active. */ - public Builder allowSystem(boolean allow) { + public @NonNull Builder allowSystem(boolean allow) { mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_SYSTEM, allow ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -573,7 +574,7 @@ public final class ZenPolicy implements Parcelable { * Whether to allow {@link PriorityCategory} sounds to play when DND is active. * @hide */ - public Builder allowCategory(@PriorityCategory int category, boolean allow) { + public @NonNull Builder allowCategory(@PriorityCategory int category, boolean allow) { switch (category) { case PRIORITY_CATEGORY_ALARMS: allowAlarms(allow); @@ -601,7 +602,7 @@ public final class ZenPolicy implements Parcelable { * Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted * by DND are shown. */ - public Builder showFullScreenIntent(boolean show) { + public @NonNull Builder showFullScreenIntent(boolean show) { mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_FULL_SCREEN_INTENT, show ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -611,7 +612,7 @@ public final class ZenPolicy implements Parcelable { * Whether {@link NotificationChannel#shouldShowLights() notification lights} from * notifications intercepted by DND are blocked. */ - public Builder showLights(boolean show) { + public @NonNull Builder showLights(boolean show) { mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_LIGHTS, show ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -620,7 +621,7 @@ public final class ZenPolicy implements Parcelable { /** * Whether notifications intercepted by DND are prevented from peeking. */ - public Builder showPeeking(boolean show) { + public @NonNull Builder showPeeking(boolean show) { mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_PEEK, show ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -630,7 +631,7 @@ public final class ZenPolicy implements Parcelable { * Whether notifications intercepted by DND are prevented from appearing in the status bar * on devices that support status bars. */ - public Builder showStatusBarIcons(boolean show) { + public @NonNull Builder showStatusBarIcons(boolean show) { mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_STATUS_BAR, show ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -640,7 +641,7 @@ public final class ZenPolicy implements Parcelable { * Whether {@link NotificationChannel#canShowBadge() badges} from * notifications intercepted by DND are allowed on devices that support badging. */ - public Builder showBadges(boolean show) { + public @NonNull Builder showBadges(boolean show) { mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_BADGE, show ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -650,7 +651,7 @@ public final class ZenPolicy implements Parcelable { * Whether notification intercepted by DND are prevented from appearing on ambient displays * on devices that support ambient display. */ - public Builder showInAmbientDisplay(boolean show) { + public @NonNull Builder showInAmbientDisplay(boolean show) { mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_AMBIENT, show ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -661,7 +662,7 @@ public final class ZenPolicy implements Parcelable { * list views like the notification shade or lockscreen on devices that support those * views. */ - public Builder showInNotificationList(boolean show) { + public @NonNull Builder showInNotificationList(boolean show) { mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_NOTIFICATION_LIST, show ? STATE_ALLOW : STATE_DISALLOW); return this; @@ -672,7 +673,7 @@ public final class ZenPolicy implements Parcelable { * {@link VisualEffect} * @hide */ - public Builder showVisualEffect(@VisualEffect int effect, boolean show) { + public @NonNull Builder showVisualEffect(@VisualEffect int effect, boolean show) { switch (effect) { case VISUAL_EFFECT_FULL_SCREEN_INTENT: showFullScreenIntent(show); @@ -1001,7 +1002,7 @@ public final class ZenPolicy implements Parcelable { * Makes deep copy of this ZenPolicy. * @hide */ - public ZenPolicy copy() { + public @NonNull ZenPolicy copy() { final Parcel parcel = Parcel.obtain(); try { writeToParcel(parcel, 0); diff --git a/core/java/android/service/textclassifier/IConversationActionsCallback.aidl b/core/java/android/service/textclassifier/IConversationActionsCallback.aidl deleted file mode 100644 index c35d4246e924..000000000000 --- a/core/java/android/service/textclassifier/IConversationActionsCallback.aidl +++ /dev/null @@ -1,28 +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.service.textclassifier; - -import android.view.textclassifier.ConversationActions; - -/** - * Callback for a ConversationActions request. - * @hide - */ -oneway interface IConversationActionsCallback { - void onSuccess(in ConversationActions conversationActions); - void onFailure(); -}
\ No newline at end of file diff --git a/core/java/android/service/textclassifier/ITextClassificationCallback.aidl b/core/java/android/service/textclassifier/ITextClassificationCallback.aidl deleted file mode 100644 index 10bfe6324509..000000000000 --- a/core/java/android/service/textclassifier/ITextClassificationCallback.aidl +++ /dev/null @@ -1,28 +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.service.textclassifier; - -import android.view.textclassifier.TextClassification; - -/** - * Callback for a TextClassification request. - * @hide - */ -oneway interface ITextClassificationCallback { - void onSuccess(in TextClassification classification); - void onFailure(); -} diff --git a/core/java/android/service/textclassifier/ITextSelectionCallback.aidl b/core/java/android/service/textclassifier/ITextClassifierCallback.aidl index 1b4c4d10d427..2926734086a5 100644 --- a/core/java/android/service/textclassifier/ITextSelectionCallback.aidl +++ b/core/java/android/service/textclassifier/ITextClassifierCallback.aidl @@ -16,13 +16,14 @@ package android.service.textclassifier; +import android.os.Bundle; import android.view.textclassifier.TextSelection; /** - * Callback for a TextSelection request. + * Callback for all requests from SystemTextClassifier. * @hide */ -oneway interface ITextSelectionCallback { - void onSuccess(in TextSelection selection); +oneway interface ITextClassifierCallback { + void onSuccess(in Bundle result); void onFailure(); }
\ No newline at end of file diff --git a/core/java/android/service/textclassifier/ITextClassifierService.aidl b/core/java/android/service/textclassifier/ITextClassifierService.aidl index 794179415fc0..2f8d67b6ccee 100644 --- a/core/java/android/service/textclassifier/ITextClassifierService.aidl +++ b/core/java/android/service/textclassifier/ITextClassifierService.aidl @@ -16,11 +16,7 @@ package android.service.textclassifier; -import android.service.textclassifier.IConversationActionsCallback; -import android.service.textclassifier.ITextClassificationCallback; -import android.service.textclassifier.ITextLanguageCallback; -import android.service.textclassifier.ITextLinksCallback; -import android.service.textclassifier.ITextSelectionCallback; +import android.service.textclassifier.ITextClassifierCallback; import android.view.textclassifier.ConversationActions; import android.view.textclassifier.SelectionEvent; import android.view.textclassifier.TextClassification; @@ -41,17 +37,17 @@ oneway interface ITextClassifierService { void onSuggestSelection( in TextClassificationSessionId sessionId, in TextSelection.Request request, - in ITextSelectionCallback callback); + in ITextClassifierCallback callback); void onClassifyText( in TextClassificationSessionId sessionId, in TextClassification.Request request, - in ITextClassificationCallback callback); + in ITextClassifierCallback callback); void onGenerateLinks( in TextClassificationSessionId sessionId, in TextLinks.Request request, - in ITextLinksCallback callback); + in ITextClassifierCallback callback); // TODO: Remove void onSelectionEvent( @@ -72,10 +68,10 @@ oneway interface ITextClassifierService { void onDetectLanguage( in TextClassificationSessionId sessionId, in TextLanguage.Request request, - in ITextLanguageCallback callback); + in ITextClassifierCallback callback); void onSuggestConversationActions( in TextClassificationSessionId sessionId, in ConversationActions.Request request, - in IConversationActionsCallback callback); + in ITextClassifierCallback callback); } diff --git a/core/java/android/service/textclassifier/ITextLanguageCallback.aidl b/core/java/android/service/textclassifier/ITextLanguageCallback.aidl deleted file mode 100644 index 263d99afca5c..000000000000 --- a/core/java/android/service/textclassifier/ITextLanguageCallback.aidl +++ /dev/null @@ -1,28 +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.service.textclassifier; - -import android.view.textclassifier.TextLanguage; - -/** - * Callback for a TextLanguage request. - * @hide - */ -oneway interface ITextLanguageCallback { - void onSuccess(in TextLanguage textLanguage); - void onFailure(); -}
\ No newline at end of file diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java index 235b8e8c9176..4088ce8ea4b0 100644 --- a/core/java/android/service/textclassifier/TextClassifierService.java +++ b/core/java/android/service/textclassifier/TextClassifierService.java @@ -17,6 +17,7 @@ package android.service.textclassifier; import android.Manifest; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -27,8 +28,12 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.os.Bundle; import android.os.CancellationSignal; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Parcelable; import android.os.RemoteException; import android.text.TextUtils; import android.util.Slog; @@ -46,6 +51,10 @@ import android.view.textclassifier.TextSelection; import com.android.internal.util.Preconditions; +import java.lang.ref.WeakReference; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + /** * Abstract base class for the TextClassifier service. * @@ -68,6 +77,11 @@ import com.android.internal.util.Preconditions; * </intent-filter> * </service>}</pre> * + * <p>From {@link android.os.Build.VERSION_CODES#Q} onward, all callbacks are called on the main + * thread. Prior to Q, there is no guarantee on what thread the callback will happen. You should + * make sure the callbacks are executed in your desired thread by using a executor, a handler or + * something else along the line. + * * @see TextClassifier * @hide */ @@ -85,201 +99,102 @@ public abstract class TextClassifierService extends Service { public static final String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService"; + /** @hide **/ + private static final String KEY_RESULT = "key_result"; + + private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper(), null, true); + private final ExecutorService mSingleThreadExecutor = Executors.newSingleThreadExecutor(); + private final ITextClassifierService.Stub mBinder = new ITextClassifierService.Stub() { // TODO(b/72533911): Implement cancellation signal @NonNull private final CancellationSignal mCancellationSignal = new CancellationSignal(); - /** {@inheritDoc} */ @Override public void onSuggestSelection( TextClassificationSessionId sessionId, - TextSelection.Request request, ITextSelectionCallback callback) { + TextSelection.Request request, ITextClassifierCallback callback) { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); - TextClassifierService.this.onSuggestSelection( - sessionId, request, mCancellationSignal, - new Callback<TextSelection>() { - @Override - public void onSuccess(TextSelection result) { - try { - callback.onSuccess(result); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - - @Override - public void onFailure(CharSequence error) { - try { - if (callback.asBinder().isBinderAlive()) { - callback.onFailure(); - } - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - }); + mMainThreadHandler.post(() -> TextClassifierService.this.onSuggestSelection( + sessionId, request, mCancellationSignal, new ProxyCallback<>(callback))); + } - /** {@inheritDoc} */ @Override public void onClassifyText( TextClassificationSessionId sessionId, - TextClassification.Request request, ITextClassificationCallback callback) { + TextClassification.Request request, ITextClassifierCallback callback) { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); - TextClassifierService.this.onClassifyText( - sessionId, request, mCancellationSignal, - new Callback<TextClassification>() { - @Override - public void onSuccess(TextClassification result) { - try { - callback.onSuccess(result); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - - @Override - public void onFailure(CharSequence error) { - try { - callback.onFailure(); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - }); + mMainThreadHandler.post(() -> TextClassifierService.this.onClassifyText( + sessionId, request, mCancellationSignal, new ProxyCallback<>(callback))); } - /** {@inheritDoc} */ @Override public void onGenerateLinks( TextClassificationSessionId sessionId, - TextLinks.Request request, ITextLinksCallback callback) { + TextLinks.Request request, ITextClassifierCallback callback) { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); - TextClassifierService.this.onGenerateLinks( - sessionId, request, - mCancellationSignal, - new Callback<TextLinks>() { - @Override - public void onSuccess(TextLinks result) { - try { - callback.onSuccess(result); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - - @Override - public void onFailure(CharSequence error) { - try { - callback.onFailure(); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - }); + mMainThreadHandler.post(() -> TextClassifierService.this.onGenerateLinks( + sessionId, request, mCancellationSignal, new ProxyCallback<>(callback))); } - /** {@inheritDoc} */ @Override public void onSelectionEvent( TextClassificationSessionId sessionId, SelectionEvent event) { Preconditions.checkNotNull(event); - TextClassifierService.this.onSelectionEvent(sessionId, event); + mMainThreadHandler.post( + () -> TextClassifierService.this.onSelectionEvent(sessionId, event)); } - /** {@inheritDoc} */ @Override public void onTextClassifierEvent( TextClassificationSessionId sessionId, TextClassifierEvent event) { Preconditions.checkNotNull(event); - TextClassifierService.this.onTextClassifierEvent(sessionId, event); + mMainThreadHandler.post( + () -> TextClassifierService.this.onTextClassifierEvent(sessionId, event)); } - /** {@inheritDoc} */ @Override public void onDetectLanguage( TextClassificationSessionId sessionId, TextLanguage.Request request, - ITextLanguageCallback callback) { + ITextClassifierCallback callback) { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); - TextClassifierService.this.onDetectLanguage( - sessionId, - request, - mCancellationSignal, - new Callback<TextLanguage>() { - @Override - public void onSuccess(TextLanguage result) { - try { - callback.onSuccess(result); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - - @Override - public void onFailure(CharSequence error) { - try { - callback.onFailure(); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - }; - }); + mMainThreadHandler.post(() -> TextClassifierService.this.onDetectLanguage( + sessionId, request, mCancellationSignal, new ProxyCallback<>(callback))); } - /** {@inheritDoc} */ @Override public void onSuggestConversationActions( TextClassificationSessionId sessionId, ConversationActions.Request request, - IConversationActionsCallback callback) { + ITextClassifierCallback callback) { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); - TextClassifierService.this.onSuggestConversationActions( - sessionId, - request, - mCancellationSignal, - new Callback<ConversationActions>() { - @Override - public void onSuccess(ConversationActions result) { - try { - callback.onSuccess(result); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - - @Override - public void onFailure(CharSequence error) { - try { - callback.onFailure(); - } catch (RemoteException e) { - Slog.d(LOG_TAG, "Error calling callback"); - } - } - }); + mMainThreadHandler.post(() -> TextClassifierService.this.onSuggestConversationActions( + sessionId, request, mCancellationSignal, new ProxyCallback<>(callback))); } - /** {@inheritDoc} */ @Override public void onCreateTextClassificationSession( TextClassificationContext context, TextClassificationSessionId sessionId) { Preconditions.checkNotNull(context); Preconditions.checkNotNull(sessionId); - TextClassifierService.this.onCreateTextClassificationSession(context, sessionId); + mMainThreadHandler.post( + () -> TextClassifierService.this.onCreateTextClassificationSession( + context, sessionId)); } - /** {@inheritDoc} */ @Override public void onDestroyTextClassificationSession(TextClassificationSessionId sessionId) { - TextClassifierService.this.onDestroyTextClassificationSession(sessionId); + mMainThreadHandler.post( + () -> TextClassifierService.this.onDestroyTextClassificationSession(sessionId)); } }; @@ -301,6 +216,7 @@ public abstract class TextClassifierService extends Service { * @param cancellationSignal object to watch for canceling the current operation * @param callback the callback to return the result to */ + @MainThread public abstract void onSuggestSelection( @Nullable TextClassificationSessionId sessionId, @NonNull TextSelection.Request request, @@ -316,6 +232,7 @@ public abstract class TextClassifierService extends Service { * @param cancellationSignal object to watch for canceling the current operation * @param callback the callback to return the result to */ + @MainThread public abstract void onClassifyText( @Nullable TextClassificationSessionId sessionId, @NonNull TextClassification.Request request, @@ -331,6 +248,7 @@ public abstract class TextClassifierService extends Service { * @param cancellationSignal object to watch for canceling the current operation * @param callback the callback to return the result to */ + @MainThread public abstract void onGenerateLinks( @Nullable TextClassificationSessionId sessionId, @NonNull TextLinks.Request request, @@ -345,12 +263,14 @@ public abstract class TextClassifierService extends Service { * @param cancellationSignal object to watch for canceling the current operation * @param callback the callback to return the result to */ + @MainThread public void onDetectLanguage( @Nullable TextClassificationSessionId sessionId, @NonNull TextLanguage.Request request, @NonNull CancellationSignal cancellationSignal, @NonNull Callback<TextLanguage> callback) { - callback.onSuccess(getLocalTextClassifier().detectLanguage(request)); + mSingleThreadExecutor.submit(() -> + callback.onSuccess(getLocalTextClassifier().detectLanguage(request))); } /** @@ -361,12 +281,14 @@ public abstract class TextClassifierService extends Service { * @param cancellationSignal object to watch for canceling the current operation * @param callback the callback to return the result to */ + @MainThread public void onSuggestConversationActions( @Nullable TextClassificationSessionId sessionId, @NonNull ConversationActions.Request request, @NonNull CancellationSignal cancellationSignal, @NonNull Callback<ConversationActions> callback) { - callback.onSuccess(getLocalTextClassifier().suggestConversationActions(request)); + mSingleThreadExecutor.submit(() -> + callback.onSuccess(getLocalTextClassifier().suggestConversationActions(request))); } /** @@ -383,6 +305,7 @@ public abstract class TextClassifierService extends Service { * instead */ @Deprecated + @MainThread public void onSelectionEvent( @Nullable TextClassificationSessionId sessionId, @NonNull SelectionEvent event) {} @@ -396,6 +319,7 @@ public abstract class TextClassifierService extends Service { * @param sessionId the session id * @param event the TextClassifier event */ + @MainThread public void onTextClassifierEvent( @Nullable TextClassificationSessionId sessionId, @NonNull TextClassifierEvent event) {} @@ -405,6 +329,7 @@ public abstract class TextClassifierService extends Service { * @param context the text classification context * @param sessionId the session's Id */ + @MainThread public void onCreateTextClassificationSession( @NonNull TextClassificationContext context, @NonNull TextClassificationSessionId sessionId) {} @@ -414,6 +339,7 @@ public abstract class TextClassifierService extends Service { * * @param sessionId the id of the session to destroy */ + @MainThread public void onDestroyTextClassificationSession( @NonNull TextClassificationSessionId sessionId) {} @@ -441,6 +367,11 @@ public abstract class TextClassifierService extends Service { return TextClassifier.NO_OP; } + /** @hide **/ + public static <T extends Parcelable> T getResponse(Bundle bundle) { + return bundle.getParcelable(KEY_RESULT); + } + /** * Callbacks for TextClassifierService results. * @@ -494,4 +425,44 @@ public abstract class TextClassifierService extends Service { si.permission)); return null; } + + /** + * Forwards the callback result to a wrapped binder callback. + */ + private static final class ProxyCallback<T extends Parcelable> implements Callback<T> { + private WeakReference<ITextClassifierCallback> mTextClassifierCallback; + + private ProxyCallback(ITextClassifierCallback textClassifierCallback) { + mTextClassifierCallback = + new WeakReference<>(Preconditions.checkNotNull(textClassifierCallback)); + } + + @Override + public void onSuccess(T result) { + ITextClassifierCallback callback = mTextClassifierCallback.get(); + if (callback == null) { + return; + } + try { + Bundle bundle = new Bundle(1); + bundle.putParcelable(KEY_RESULT, result); + callback.onSuccess(bundle); + } catch (RemoteException e) { + Slog.d(LOG_TAG, "Error calling callback"); + } + } + + @Override + public void onFailure(CharSequence error) { + ITextClassifierCallback callback = mTextClassifierCallback.get(); + if (callback == null) { + return; + } + try { + callback.onFailure(); + } catch (RemoteException e) { + Slog.d(LOG_TAG, "Error calling callback"); + } + } + } } diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java index a5d5af2433fe..7fb0f950f583 100644 --- a/core/java/android/text/style/LineHeightSpan.java +++ b/core/java/android/text/style/LineHeightSpan.java @@ -88,7 +88,7 @@ public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan { /** * Constructor called from {@link TextUtils} to restore the span from a parcel */ - public Standard(Parcel src) { + public Standard(@NonNull Parcel src) { mHeight = src.readInt(); } diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING new file mode 100644 index 000000000000..87d428ab551e --- /dev/null +++ b/core/java/android/view/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "CtsUiRenderingTestCases" + }, + { + "name": "CtsAccelerationTestCases" + } + ] +}
\ No newline at end of file diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 877b3044f7c3..874be814ed9a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -18589,7 +18589,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @FlagMap(target = FADING_EDGE_VERTICAL, name = "vertical"), @FlagMap(target = FADING_EDGE_HORIZONTAL, name = "horizontal") }) - int getFadingEdge() { + public int getFadingEdge() { return mViewFlags & FADING_EDGE_MASK; } @@ -18600,7 +18600,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ @InspectableProperty - int getFadingEdgeLength() { + public int getFadingEdgeLength() { if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { return mScrollCache.fadingEdgeLength; } diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index 135a8912fc60..f3bbca3500c7 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -22,6 +22,7 @@ import static android.view.WindowInsets.Type.IME; import static android.view.WindowInsets.Type.LAST; import static android.view.WindowInsets.Type.SIDE_BARS; import static android.view.WindowInsets.Type.SIZE; +import static android.view.WindowInsets.Type.SYSTEM_GESTURES; import static android.view.WindowInsets.Type.TOP_BAR; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.compatSystemInsets; @@ -35,7 +36,6 @@ import android.annotation.UnsupportedAppUsage; import android.graphics.Insets; import android.graphics.Rect; import android.util.SparseArray; -import android.view.InsetsState.InternalInsetType; import android.view.WindowInsets.Type.InsetType; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethod; @@ -229,6 +229,7 @@ public final class WindowInsets { static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) { typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0); typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom); + typeInsetMap[indexOf(SYSTEM_GESTURES)] = Insets.of(insets); } private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetMap) { @@ -630,6 +631,28 @@ public final class WindowInsets { } /** + * Returns the system gesture insets. + * + * <p>The system gesture insets represent the area of a window where system gestures have + * priority and may consume some or all touch input, e.g. due to the a system bar + * occupying it, or it being reserved for touch-only gestures. + * + * <p>Simple taps are guaranteed to reach the window even within the system gesture insets, + * as long as they are outside the {@link #getSystemWindowInsets() system window insets}. + * + * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned + * even when the system gestures are inactive due to + * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or + * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}. + * + * <p>This inset does not affect the result of {@link #isConsumed()} and cannot be consumed. + */ + @NonNull + public Insets getSystemGestureInsets() { + return getInsets(mTypeInsetsMap, SYSTEM_GESTURES); + } + + /** * Returns a copy of this WindowInsets with the stable insets fully consumed. * * @return A modified copy of this WindowInsets @@ -853,6 +876,22 @@ public final class WindowInsets { } /** + * Sets system gesture insets in pixels. + * + * <p>The system gesture insets represent the area of a window where system gestures have + * priority and may consume some or all touch input, e.g. due to the a system bar + * occupying it, or it being reserved for touch-only gestures. + * + * @see #getSystemGestureInsets() + * @return itself + */ + @NonNull + public Builder setSystemGestureInsets(@NonNull Insets insets) { + WindowInsets.setInsets(mTypeInsetsMap, SYSTEM_GESTURES, insets); + return this; + } + + /** * Sets the insets of a specific window type in pixels. * * <p>The insets represents the area of a a window that is partially or fully obscured by @@ -1005,8 +1044,10 @@ public final class WindowInsets { static final int IME = 0x2; static final int SIDE_BARS = 0x4; - static final int LAST = 0x8; - static final int SIZE = 4; + static final int SYSTEM_GESTURES = 0x8; + + static final int LAST = 0x10; + static final int SIZE = 5; static final int WINDOW_DECOR = LAST; static int indexOf(@InsetType int type) { @@ -1017,8 +1058,10 @@ public final class WindowInsets { return 1; case SIDE_BARS: return 2; - case WINDOW_DECOR: + case SYSTEM_GESTURES: return 3; + case WINDOW_DECOR: + return 4; default: throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST," + " type=" + type); @@ -1030,7 +1073,7 @@ public final class WindowInsets { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR }) + @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES }) public @interface InsetType { } @@ -1064,6 +1107,27 @@ public final class WindowInsets { } /** + * Returns an inset type representing the system gesture insets. + * + * <p>The system gesture insets represent the area of a window where system gestures have + * priority and may consume some or all touch input, e.g. due to the a system bar + * occupying it, or it being reserved for touch-only gestures. + * + * <p>Simple taps are guaranteed to reach the window even within the system gesture insets, + * as long as they are outside the {@link #getSystemWindowInsets() system window insets}. + * + * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned + * even when the system gestures are inactive due to + * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or + * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}. + * + * @see #getSystemGestureInsets() + */ + public static @InsetType int systemGestures() { + return SYSTEM_GESTURES; + } + + /** * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but * not {@link #ime()}. */ @@ -1082,6 +1146,9 @@ public final class WindowInsets { /** * @return All inset types combined. + * + * TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and + * {@link #ime()} does not seem very useful. */ public static @InsetType int all() { return 0xFFFFFFFF; diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java index 86f85bfecc85..b9dc0dd99a1d 100644 --- a/core/java/android/view/contentcapture/ContentCaptureContext.java +++ b/core/java/android/view/contentcapture/ContentCaptureContext.java @@ -24,7 +24,6 @@ import android.app.TaskInfo; import android.content.ComponentName; import android.content.Context; import android.content.LocusId; -import android.net.Uri; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -212,11 +211,11 @@ public final class ContentCaptureContext implements Parcelable { } /** - * Helper that creates a {@link ContentCaptureContext} associated with the given {@code uri}. + * Helper that creates a {@link ContentCaptureContext} associated with the given {@code id}. */ @NonNull - public static ContentCaptureContext forLocusId(@NonNull Uri uri) { - return new Builder(new LocusId(uri)).build(); + public static ContentCaptureContext forLocusId(@NonNull String id) { + return new Builder(new LocusId(id)).build(); } /** diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.java b/core/java/android/view/contentcapture/UserDataRemovalRequest.java index b273f7c15c01..3e1e4abaa84c 100644 --- a/core/java/android/view/contentcapture/UserDataRemovalRequest.java +++ b/core/java/android/view/contentcapture/UserDataRemovalRequest.java @@ -15,6 +15,7 @@ */ package android.view.contentcapture; +import android.annotation.IntDef; import android.annotation.NonNull; import android.app.ActivityThread; import android.content.LocusId; @@ -24,6 +25,8 @@ import android.util.IntArray; import com.android.internal.util.Preconditions; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -33,6 +36,19 @@ import java.util.List; */ public final class UserDataRemovalRequest implements Parcelable { + /** + * When set, service should use the {@link LocusId#getId()} as prefix for the data to be + * removed. + */ + public static final int FLAG_IS_PREFIX = 0x1; + + /** @hide */ + @IntDef(prefix = { "FLAG" }, flag = true, value = { + FLAG_IS_PREFIX + }) + @Retention(RetentionPolicy.SOURCE) + @interface Flags {} + private final String mPackageName; private final boolean mForEverything; @@ -46,7 +62,7 @@ public final class UserDataRemovalRequest implements Parcelable { mLocusIdRequests = new ArrayList<>(size); for (int i = 0; i < size; i++) { mLocusIdRequests.add(new LocusIdRequest(builder.mLocusIds.get(i), - builder.mRecursive.get(i) == 1)); + builder.mFlags.get(i))); } } } @@ -59,7 +75,7 @@ public final class UserDataRemovalRequest implements Parcelable { mLocusIdRequests = new ArrayList<>(size); for (int i = 0; i < size; i++) { mLocusIdRequests.add(new LocusIdRequest((LocusId) parcel.readValue(null), - parcel.readBoolean())); + parcel.readInt())); } } } @@ -94,7 +110,7 @@ public final class UserDataRemovalRequest implements Parcelable { private boolean mForEverything; private ArrayList<LocusId> mLocusIds; - private IntArray mRecursive; + private IntArray mFlags; private boolean mDestroyed; @@ -116,24 +132,24 @@ 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 recursive whether it should remove the data associated with just the - * {@code LocusId} or its tree of descendants. + * @param flags either {@link UserDataRemovalRequest#FLAG_IS_PREFIX} or {@code 0} * * @return this builder */ @NonNull - public Builder addLocusId(@NonNull LocusId locusId, boolean recursive) { + public Builder addLocusId(@NonNull LocusId locusId, @Flags int flags) { throwIfDestroyed(); Preconditions.checkState(!mForEverything, "Already is for everything"); Preconditions.checkNotNull(locusId); + // felipeal: check flags if (mLocusIds == null) { mLocusIds = new ArrayList<>(); - mRecursive = new IntArray(); + mFlags = new IntArray(); } mLocusIds.add(locusId); - mRecursive.add(recursive ? 1 : 0); + mFlags.add(flags); return this; } @@ -144,7 +160,8 @@ public final class UserDataRemovalRequest implements Parcelable { public UserDataRemovalRequest build() { throwIfDestroyed(); - Preconditions.checkState(mForEverything || mLocusIds != null); + Preconditions.checkState(mForEverything || mLocusIds != null, + "must call either #forEverything() or add one #addLocusId()"); mDestroyed = true; return new UserDataRemovalRequest(this); @@ -170,7 +187,7 @@ public final class UserDataRemovalRequest implements Parcelable { for (int i = 0; i < size; i++) { final LocusIdRequest request = mLocusIdRequests.get(i); parcel.writeValue(request.getLocusId()); - parcel.writeBoolean(request.isRecursive()); + parcel.writeInt(request.getFlags()); } } } @@ -196,11 +213,11 @@ public final class UserDataRemovalRequest implements Parcelable { */ public final class LocusIdRequest { private final @NonNull LocusId mLocusId; - private final boolean mRecursive; + private final @Flags int mFlags; - private LocusIdRequest(@NonNull LocusId locusId, boolean recursive) { + private LocusIdRequest(@NonNull LocusId locusId, @Flags int flags) { this.mLocusId = locusId; - this.mRecursive = recursive; + this.mFlags = flags; } /** @@ -212,12 +229,13 @@ public final class UserDataRemovalRequest implements Parcelable { } /** - * Checks whether the request is to remove just the data associated with the {@link LocusId} - * per se, or also its descendants. + * Gets the flags associates with request. + * + * @return either {@link UserDataRemovalRequest#FLAG_IS_PREFIX} or {@code 0}. */ @NonNull - public boolean isRecursive() { - return mRecursive; + public @Flags int getFlags() { + return mFlags; } } } diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java index f85952108f07..30938c152eca 100644 --- a/core/java/android/view/inspector/InspectableProperty.java +++ b/core/java/android/view/inspector/InspectableProperty.java @@ -16,6 +16,7 @@ package android.view.inspector; +import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -39,7 +40,7 @@ import java.lang.annotation.Target; * @see InspectionCompanion#readProperties(Object, PropertyReader) * @hide */ -@Target({METHOD}) +@Target({METHOD, FIELD}) @Retention(SOURCE) @TestApi public @interface InspectableProperty { diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java index 8b370f543ccc..8f8766e3f783 100644 --- a/core/java/android/view/textclassifier/SystemTextClassifier.java +++ b/core/java/android/view/textclassifier/SystemTextClassifier.java @@ -20,15 +20,14 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.content.Context; +import android.os.Bundle; import android.os.Looper; +import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; -import android.service.textclassifier.IConversationActionsCallback; -import android.service.textclassifier.ITextClassificationCallback; +import android.service.textclassifier.ITextClassifierCallback; import android.service.textclassifier.ITextClassifierService; -import android.service.textclassifier.ITextLanguageCallback; -import android.service.textclassifier.ITextLinksCallback; -import android.service.textclassifier.ITextSelectionCallback; +import android.service.textclassifier.TextClassifierService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; @@ -73,9 +72,10 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { request.setCallingPackageName(mPackageName); - final TextSelectionCallback callback = new TextSelectionCallback(); + final BlockingCallback<TextSelection> callback = + new BlockingCallback<>("textselection"); mManagerService.onSuggestSelection(mSessionId, request, callback); - final TextSelection selection = callback.mReceiver.get(); + final TextSelection selection = callback.get(); if (selection != null) { return selection; } @@ -95,9 +95,10 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { request.setCallingPackageName(mPackageName); - final TextClassificationCallback callback = new TextClassificationCallback(); + final BlockingCallback<TextClassification> callback = + new BlockingCallback<>("textclassification"); mManagerService.onClassifyText(mSessionId, request, callback); - final TextClassification classification = callback.mReceiver.get(); + final TextClassification classification = callback.get(); if (classification != null) { return classification; } @@ -122,9 +123,10 @@ public final class SystemTextClassifier implements TextClassifier { try { request.setCallingPackageName(mPackageName); - final TextLinksCallback callback = new TextLinksCallback(); + final BlockingCallback<TextLinks> callback = + new BlockingCallback<>("textlinks"); mManagerService.onGenerateLinks(mSessionId, request, callback); - final TextLinks links = callback.mReceiver.get(); + final TextLinks links = callback.get(); if (links != null) { return links; } @@ -165,9 +167,10 @@ public final class SystemTextClassifier implements TextClassifier { try { request.setCallingPackageName(mPackageName); - final TextLanguageCallback callback = new TextLanguageCallback(); + final BlockingCallback<TextLanguage> callback = + new BlockingCallback<>("textlanguage"); mManagerService.onDetectLanguage(mSessionId, request, callback); - final TextLanguage textLanguage = callback.mReceiver.get(); + final TextLanguage textLanguage = callback.get(); if (textLanguage != null) { return textLanguage; } @@ -184,9 +187,10 @@ public final class SystemTextClassifier implements TextClassifier { try { request.setCallingPackageName(mPackageName); - final ConversationActionsCallback callback = new ConversationActionsCallback(); + final BlockingCallback<ConversationActions> callback = + new BlockingCallback<>("conversation-actions"); mManagerService.onSuggestConversationActions(mSessionId, request, callback); - final ConversationActions conversationActions = callback.mReceiver.get(); + final ConversationActions conversationActions = callback.get(); if (conversationActions != null) { return conversationActions; } @@ -245,82 +249,28 @@ public final class SystemTextClassifier implements TextClassifier { } } - private static final class TextSelectionCallback extends ITextSelectionCallback.Stub { + private static final class BlockingCallback<T extends Parcelable> + extends ITextClassifierCallback.Stub { + private final ResponseReceiver<T> mReceiver; - final ResponseReceiver<TextSelection> mReceiver = new ResponseReceiver<>("textselection"); - - @Override - public void onSuccess(TextSelection selection) { - mReceiver.onSuccess(selection); + BlockingCallback(String name) { + mReceiver = new ResponseReceiver<>(name); } @Override - public void onFailure() { - mReceiver.onFailure(); - } - } - - private static final class TextClassificationCallback extends ITextClassificationCallback.Stub { - - final ResponseReceiver<TextClassification> mReceiver = - new ResponseReceiver<>("textclassification"); - - @Override - public void onSuccess(TextClassification classification) { - mReceiver.onSuccess(classification); + public void onSuccess(Bundle result) { + mReceiver.onSuccess(TextClassifierService.getResponse(result)); } @Override public void onFailure() { mReceiver.onFailure(); } - } - private static final class TextLinksCallback extends ITextLinksCallback.Stub { - - final ResponseReceiver<TextLinks> mReceiver = new ResponseReceiver<>("textlinks"); - - @Override - public void onSuccess(TextLinks links) { - mReceiver.onSuccess(links); - } - - @Override - public void onFailure() { - mReceiver.onFailure(); - } - } - - private static final class TextLanguageCallback extends ITextLanguageCallback.Stub { - - final ResponseReceiver<TextLanguage> mReceiver = new ResponseReceiver<>("textlanguage"); - - @Override - public void onSuccess(TextLanguage textLanguage) { - mReceiver.onSuccess(textLanguage); - } - - @Override - public void onFailure() { - mReceiver.onFailure(); - } - } - - private static final class ConversationActionsCallback - extends IConversationActionsCallback.Stub { - - final ResponseReceiver<ConversationActions> mReceiver = - new ResponseReceiver<>("conversationaction"); - - @Override - public void onSuccess(ConversationActions conversationActions) { - mReceiver.onSuccess(conversationActions); + public T get() { + return mReceiver.get(); } - @Override - public void onFailure() { - mReceiver.onFailure(); - } } private static final class ResponseReceiver<T> { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 73792b08194b..04bcb1451b61 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -12744,7 +12744,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * return value may not be the same as the one TextView uses if the View's layout direction is * not resolved or detached from parent root view. */ - public TextDirectionHeuristic getTextDirectionHeuristic() { + public @NonNull TextDirectionHeuristic getTextDirectionHeuristic() { if (hasPasswordTransformationMethod()) { // passwords fields should be LTR return TextDirectionHeuristics.LTR; diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index f3bc2c7fa513..445075da7f90 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -616,7 +616,7 @@ enum Action { // OS: Q ACTION_PANEL_INTERACTION = 1658; - // ACTION: Show Contextual homepage, log latency in loading cards + // ACTION: Show Contextual homepage. Log total loading latency. ACTION_CONTEXTUAL_HOME_SHOW = 1662; // ACTION: Contextual card displays @@ -649,6 +649,15 @@ enum Action { ACTION_ATCSCUC = 1680; ACTION_ATCHNUC = 1681; + + // ACTION: Individual contextual card loading time + ACTION_CONTEXTUAL_CARD_LOAD = 1684; + + //ACTION: Contextual card loading timeout + ACTION_CONTEXTUAL_CARD_LOAD_TIMEOUT = 1685; + + //ACTION: Log result for each card's eligibility check + ACTION_CONTEXTUAL_CARD_ELIGIBILITY = 1686; } /** @@ -2287,4 +2296,7 @@ enum PageId { // OPEN: Accessibility detail settings (android.settings.ACCESSIBILITY_DETAILS_SETTINGS intent) ACCESSIBILITY_DETAILS_SETTINGS = 1682; + + // Open: Settings will show the conditional when Grayscale mode is on + SETTINGS_CONDITION_GRAYSCALE_MODE = 1683; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 63e0d03779b0..4c4393d4fd61 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3139,6 +3139,14 @@ <permission android:name="android.permission.BIND_CONTENT_CAPTURE_SERVICE" android:protectionLevel="signature" /> + <!-- Must be required by a android.service.contentsuggestions.ContentSuggestionsService, + to ensure that only the system can bind to it. + @SystemApi @hide This is not a third-party API (intended for OEMs and system apps). + <p>Protection level: signature + --> + <permission android:name="android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE" + android:protectionLevel="signature" /> + <!-- Must be required by a android.service.autofill.augmented.AugmentedAutofillService, to ensure that only the system can bind to it. @SystemApi @hide This is not a third-party API (intended for OEMs and system apps). @@ -4445,10 +4453,12 @@ @hide --> <permission android:name="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY" android:protectionLevel="signature|preinstalled" /> + <!-- @SystemApi Allows wallpaper to be rendered in ambient mode. @hide --> <permission android:name="android.permission.AMBIENT_WALLPAPER" android:protectionLevel="signature|preinstalled" /> + <!-- @SystemApi Allows sensor privacy to be modified. @hide --> <permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" @@ -4459,6 +4469,12 @@ <permission android:name="android.permission.REVIEW_ACCESSIBILITY_SERVICES" android:protectionLevel="signature" /> + <!-- @SystemApi Allows an activity to replace the app name and icon displayed in share targets + in the sharesheet for the Q-release and later. + @hide <p>Not for use by third-party applications.</p> --> + <permission android:name="android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON" + android:protectionLevel="signature|privileged" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 47e546210103..2f2fdca7f279 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3945,4 +3945,7 @@ and a second time clipped to the fill level to indicate charge --> <bool name="config_batterymeterDualTone">false</bool> + <!-- The default peak refresh rate for a given device. Change this value if you want to allow + for higher refresh rates to be automatically used out of the box --> + <integer name="config_defaultPeakRefreshRate">60</integer> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 426d813885fe..d5444c0e760c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3688,4 +3688,6 @@ <java-symbol type="string" name="mime_type_spreadsheet_ext" /> <java-symbol type="string" name="mime_type_presentation" /> <java-symbol type="string" name="mime_type_presentation_ext" /> + + <java-symbol type="integer" name="config_defaultPeakRefreshRate" /> </resources> diff --git a/core/tests/BroadcastRadioTests/Android.mk b/core/tests/BroadcastRadioTests/Android.mk index 6b0484ec366d..faffc4b28a58 100644 --- a/core/tests/BroadcastRadioTests/Android.mk +++ b/core/tests/BroadcastRadioTests/Android.mk @@ -25,7 +25,7 @@ LOCAL_MODULE_TAGS := tests # LOCAL_SDK_VERSION := current LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util androidx.test.rules testng +LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt androidx.test.rules testng LOCAL_JAVA_LIBRARIES := android.test.base diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 69632c1d4167..ad1403db242c 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -92,7 +92,8 @@ public class SettingsBackupTest { Settings.System.VOLUME_SYSTEM, // deprecated since API 2? Settings.System.VOLUME_VOICE, // deprecated since API 2? Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug? - Settings.System.WINDOW_ORIENTATION_LISTENER_LOG // used for debugging only + Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only + Settings.System.PEAK_REFRESH_RATE // depends on hardware capabilities ); private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS = @@ -131,6 +132,7 @@ public class SettingsBackupTest { Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, Settings.Global.AUTOMATIC_POWER_SAVER_MODE, Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, + Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST, Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY, Settings.Global.BROADCAST_BG_CONSTANTS, Settings.Global.BROADCAST_FG_CONSTANTS, diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java index a5ac2707b620..de2edc3637e4 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java @@ -25,7 +25,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.testng.Assert.assertThrows; import android.content.LocusId; -import android.net.Uri; import android.os.Parcel; import android.os.SystemClock; import android.view.autofill.AutofillId; @@ -47,7 +46,7 @@ public class ContentCaptureEventTest { private static final long MY_EPOCH = SystemClock.uptimeMillis(); - private static final LocusId ID = new LocusId(Uri.parse("WHATEVER")); + private static final LocusId ID = new LocusId("WHATEVER"); // Not using @Mock because it's final - no need to be fancy here.... private final ContentCaptureContext mClientContext = diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml index 2110a8fa7e3d..3e53a3838543 100644 --- a/data/etc/com.android.settings.xml +++ b/data/etc/com.android.settings.xml @@ -33,6 +33,7 @@ <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE" /> <permission name="android.permission.MASTER_CLEAR"/> + <permission name="android.permission.MEDIA_CONTENT_CONTROL"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <permission name="android.permission.MOVE_PACKAGE"/> diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index e6233548651e..7345ea4db43d 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -193,7 +193,7 @@ public class HardwareRenderer { * * @param name The debug name to use for this HardwareRenderer instance */ - public void setName(String name) { + public void setName(@NonNull String name) { nSetName(mNativeProxy, name); } @@ -330,7 +330,7 @@ public class HardwareRenderer { * * @return this instance */ - public FrameRenderRequest setVsyncTime(long vsyncTime) { + public @NonNull FrameRenderRequest setVsyncTime(long vsyncTime) { mFrameInfo.setVsync(vsyncTime, vsyncTime); mFrameInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS); return this; @@ -351,7 +351,7 @@ public class HardwareRenderer { * * @return this instance */ - public FrameRenderRequest setFrameCommitCallback(@NonNull Executor executor, + public @NonNull FrameRenderRequest setFrameCommitCallback(@NonNull Executor executor, @NonNull Runnable frameCommitCallback) { setFrameCompleteCallback(frameNr -> executor.execute(frameCommitCallback)); return this; @@ -372,7 +372,7 @@ public class HardwareRenderer { * completion. * @return this instance */ - public FrameRenderRequest setWaitForPresent(boolean shouldWait) { + public @NonNull FrameRenderRequest setWaitForPresent(boolean shouldWait) { mWaitForPresent = shouldWait; return this; } @@ -406,7 +406,7 @@ public class HardwareRenderer { * @return An instance of {@link FrameRenderRequest}. The instance may be reused for every * frame, so the caller should not hold onto it for longer than a single render request. */ - public FrameRenderRequest createRenderRequest() { + public @NonNull FrameRenderRequest createRenderRequest() { mRenderRequest.reset(); return mRenderRequest; } diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 7016cc741e90..2cf802bb9631 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -59,6 +59,8 @@ import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; import java.nio.ByteBuffer; +import java.util.Locale; +import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; @@ -838,6 +840,40 @@ public final class ImageDecoder implements AutoCloseable { } /** + * Return if the given MIME type is a supported file format that can be + * decoded by this class. This can be useful to determine if a file can be + * decoded directly, or if it needs to be converted into a more general + * format using an API like {@link ContentResolver#openTypedAssetFile}. + */ + public static boolean isMimeTypeSupported(@NonNull String mimeType) { + Objects.requireNonNull(mimeType); + switch (mimeType.toLowerCase(Locale.US)) { + case "image/png": + case "image/jpeg": + case "image/webp": + case "image/gif": + case "image/heif": + case "image/heic": + case "image/bmp": + case "image/x-ico": + case "image/vnd.wap.wbmp": + case "image/x-sony-arw": + case "image/x-canon-cr2": + case "image/x-adobe-dng": + case "image/x-nikon-nef": + case "image/x-nikon-nrw": + case "image/x-olympus-orf": + case "image/x-fuji-raf": + case "image/x-panasonic-rw2": + case "image/x-pentax-pef": + case "image/x-samsung-srw": + return true; + default: + return false; + } + } + + /** * Create a new {@link Source Source} from a resource. * * @param res the {@link Resources} object containing the image data. diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 42b6acd3b25a..c3bcbb45c2b4 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -62,7 +62,7 @@ import java.lang.annotation.RetentionPolicy; * * <h3>Creating a RenderNode</h3> * <pre class="prettyprint"> - * RenderNode renderNode = RenderNode.create("myRenderNode"); + * RenderNode renderNode = new RenderNode("myRenderNode"); * renderNode.setLeftTopRightBottom(0, 0, 50, 50); // Set the size to 50x50 * RecordingCanvas canvas = renderNode.beginRecording(); * try { @@ -106,7 +106,7 @@ import java.lang.annotation.RetentionPolicy; * * <pre class="prettyprint"> * private void createDisplayList() { - * mRenderNode = RenderNode.create("MyRenderNode"); + * mRenderNode = new RenderNode("MyRenderNode"); * mRenderNode.setLeftTopRightBottom(0, 0, width, height); * RecordingCanvas canvas = mRenderNode.beginRecording(); * try { @@ -338,7 +338,7 @@ public final class RenderNode { * @see #endRecording() * @see #hasDisplayList() */ - public RecordingCanvas beginRecording(int width, int height) { + public @NonNull RecordingCanvas beginRecording(int width, int height) { if (mCurrentRecordingCanvas != null) { throw new IllegalStateException( "Recording currently in progress - missing #endRecording() call?"); @@ -358,7 +358,7 @@ public final class RenderNode { * @see #endRecording() * @see #hasDisplayList() */ - public RecordingCanvas beginRecording() { + public @NonNull RecordingCanvas beginRecording() { return beginRecording(nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode)); } @@ -1285,7 +1285,7 @@ public final class RenderNode { * @param position The position rectangle in pixels * @return True if the value changed, false if the new value was the same as the previous value. */ - public boolean setPosition(Rect position) { + public boolean setPosition(@NonNull Rect position) { return nSetLeftTopRightBottom(mNativeRenderNode, position.left, position.top, position.right, position.bottom); } diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 2855227a1002..f67188c22609 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -256,7 +256,7 @@ public class StateListDrawable extends DrawableContainer { * @see #getStateCount() * @see #getStateDrawable(int) */ - public int[] getStateSet(int index) { + public @NonNull int[] getStateSet(int index) { return mStateListState.mStateSets[index]; } @@ -268,7 +268,7 @@ public class StateListDrawable extends DrawableContainer { * @see #getStateCount() * @see #getStateSet(int) */ - public Drawable getStateDrawable(int index) { + public @Nullable Drawable getStateDrawable(int index) { return mStateListState.getChild(index); } @@ -280,7 +280,7 @@ public class StateListDrawable extends DrawableContainer { * @see #getStateDrawable(int) * @see #getStateSet(int) */ - public int findStateDrawableIndex(int[] stateSet) { + public int findStateDrawableIndex(@NonNull int[] stateSet) { return mStateListState.indexOfStateSet(stateSet); } diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk index 596e5f530970..99d3197f8bf3 100644 --- a/keystore/tests/Android.mk +++ b/keystore/tests/Android.mk @@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test + androidx.test.rules hamcrest-library LOCAL_PACKAGE_NAME := KeystoreTests LOCAL_PRIVATE_PLATFORM_APIS := true diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml index 9bf2d0c761e6..6833cd1e35b9 100644 --- a/keystore/tests/AndroidManifest.xml +++ b/keystore/tests/AndroidManifest.xml @@ -20,7 +20,7 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.security.tests" android:label="Tests for Keystore"> </instrumentation> diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java index 32f8ec44d11f..fca2775a34bb 100644 --- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java @@ -22,16 +22,20 @@ import static org.junit.Assert.assertThat; import android.os.Parcel; import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.ParcelableKeyGenParameterSpec; import android.security.keystore.KeyProperties; -import android.support.test.runner.AndroidJUnit4; +import android.security.keystore.ParcelableKeyGenParameterSpec; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + import java.math.BigInteger; import java.security.spec.ECGenParameterSpec; import java.security.spec.RSAKeyGenParameterSpec; import java.util.Date; + import javax.security.auth.x500.X500Principal; -import org.junit.Test; -import org.junit.runner.RunWith; /** Unit tests for {@link ParcelableKeyGenParameterSpec}. */ @RunWith(AndroidJUnit4.class) diff --git a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java index 865cad472eb5..b2edfd05d13f 100644 --- a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java @@ -20,10 +20,12 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import android.security.ParcelableKeyGenParameterSpecTest; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; -import android.security.ParcelableKeyGenParameterSpecTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 117d05e837ef..d74f27cca200 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -1052,6 +1052,8 @@ void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) { } void AssetManager2::InvalidateCaches(uint32_t diff) { + cached_bag_resid_stacks_.clear(); + if (diff == 0xffffffffu) { // Everything must go. cached_bags_.clear(); diff --git a/libs/hwui/TEST_MAPPING b/libs/hwui/TEST_MAPPING new file mode 100644 index 000000000000..d9f2acbb49d2 --- /dev/null +++ b/libs/hwui/TEST_MAPPING @@ -0,0 +1,13 @@ +{ + "presubmit": [ + { + "name": "CtsUiRenderingTestCases" + }, + { + "name": "CtsGraphicsTestCases" + }, + { + "name": "CtsAccelerationTestCases" + } + ] +}
\ No newline at end of file diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h index 5e8eac1833ce..f056d3b6c9e8 100644 --- a/libs/incident/include/android/os/IncidentReportArgs.h +++ b/libs/incident/include/android/os/IncidentReportArgs.h @@ -47,12 +47,16 @@ public: void setAll(bool all); void setDest(int dest); void addSection(int section); + void setReceiverPkg(const string& pkg); + void setReceiverCls(const string& cls); void addHeader(const vector<uint8_t>& headerProto); inline bool all() const { return mAll; } bool containsSection(int section) const; inline int dest() const { return mDest; } inline const set<int>& sections() const { return mSections; } + inline const String16& receiverPkg() const { return mReceiverPkg; } + inline const String16& receiverCls() const { return mReceiverCls; } inline const vector<vector<uint8_t>>& headers() const { return mHeaders; } void merge(const IncidentReportArgs& that); @@ -62,6 +66,8 @@ private: vector<vector<uint8_t>> mHeaders; bool mAll; int mDest; + String16 mReceiverPkg; + String16 mReceiverCls; }; } diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp index 06b7a5b682b1..46c8dcf967d7 100644 --- a/libs/incident/src/IncidentReportArgs.cpp +++ b/libs/incident/src/IncidentReportArgs.cpp @@ -81,6 +81,16 @@ IncidentReportArgs::writeToParcel(Parcel* out) const return err; } + err = out->writeString16(mReceiverPkg); + if (err != NO_ERROR) { + return err; + } + + err = out->writeString16(mReceiverCls); + if (err != NO_ERROR) { + return err; + } + return NO_ERROR; } @@ -134,6 +144,9 @@ IncidentReportArgs::readFromParcel(const Parcel* in) } mDest = dest; + mReceiverPkg = in->readString16(); + mReceiverCls = in->readString16(); + return OK; } @@ -161,6 +174,18 @@ IncidentReportArgs::addSection(int section) } void +IncidentReportArgs::setReceiverPkg(const string& pkg) +{ + mReceiverPkg = String16(pkg.c_str()); +} + +void +IncidentReportArgs::setReceiverCls(const string& cls) +{ + mReceiverCls = String16(cls.c_str()); +} + +void IncidentReportArgs::addHeader(const vector<uint8_t>& headerProto) { mHeaders.push_back(headerProto); diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index ed74333da895..17e25097cef8 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -113,10 +113,6 @@ public class Location implements Parcelable { * Bit mask for mFieldsMask indicating the presence of mBearingAccuracy. */ private static final int HAS_BEARING_ACCURACY_MASK = 128; - /** - * Bit mask for mFieldsMask indicating the presence of mElapsedRealtimeUncertaintyNanos. - */ - private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 256; // Cached data to make bearing/distance computations more efficient for the case // where distanceTo and bearingTo are called in sequence. Assume this typically happens @@ -134,9 +130,6 @@ public class Location implements Parcelable { private long mTime = 0; @UnsupportedAppUsage private long mElapsedRealtimeNanos = 0; - // Estimate of the relative precision of the alignment of this SystemClock - // timestamp, with the reported measurements in nanoseconds (68% confidence). - private long mElapsedRealtimeUncertaintyNanos = 0; private double mLatitude = 0.0; private double mLongitude = 0.0; private double mAltitude = 0.0f; @@ -178,7 +171,6 @@ public class Location implements Parcelable { mProvider = l.mProvider; mTime = l.mTime; mElapsedRealtimeNanos = l.mElapsedRealtimeNanos; - mElapsedRealtimeUncertaintyNanos = l.mElapsedRealtimeUncertaintyNanos; mFieldsMask = l.mFieldsMask; mLatitude = l.mLatitude; mLongitude = l.mLongitude; @@ -199,7 +191,6 @@ public class Location implements Parcelable { mProvider = null; mTime = 0; mElapsedRealtimeNanos = 0; - mElapsedRealtimeUncertaintyNanos = 0; mFieldsMask = 0; mLatitude = 0; mLongitude = 0; @@ -595,37 +586,6 @@ public class Location implements Parcelable { } /** - * Get estimate of the relative precision of the alignment of the - * ElapsedRealtimeNanos timestamp, with the reported measurements in - * nanoseconds (68% confidence). - * - * @return uncertainty of elapsed real-time of fix, in nanoseconds. - */ - public long getElapsedRealtimeUncertaintyNanos() { - return mElapsedRealtimeUncertaintyNanos; - } - - /** - * Set estimate of the relative precision of the alignment of the - * ElapsedRealtimeNanos timestamp, with the reported measurements in - * nanoseconds (68% confidence). - * - * @param time uncertainty of the elapsed real-time of fix, in nanoseconds. - */ - public void setElapsedRealtimeUncertaintyNanos(long time) { - mElapsedRealtimeUncertaintyNanos = time; - mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK; - } - - /** - * True if this location has a elapsed realtime accuracy. - */ - public boolean hasElapsedRealtimeUncertaintyNanos() { - return (mFieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0; - } - - - /** * Get the latitude, in degrees. * * <p>All locations generated by the {@link LocationManager} @@ -1102,10 +1062,6 @@ public class Location implements Parcelable { s.append(" et="); TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s); } - if (hasElapsedRealtimeUncertaintyNanos()) { - s.append(" etAcc="); - TimeUtils.formatDuration(mElapsedRealtimeUncertaintyNanos / 1000000L, s); - } if (hasAltitude()) s.append(" alt=").append(mAltitude); if (hasSpeed()) s.append(" vel=").append(mSpeed); if (hasBearing()) s.append(" bear=").append(mBearing); @@ -1136,7 +1092,6 @@ public class Location implements Parcelable { Location l = new Location(provider); l.mTime = in.readLong(); l.mElapsedRealtimeNanos = in.readLong(); - l.mElapsedRealtimeUncertaintyNanos = in.readLong(); l.mFieldsMask = in.readByte(); l.mLatitude = in.readDouble(); l.mLongitude = in.readDouble(); @@ -1167,7 +1122,6 @@ public class Location implements Parcelable { parcel.writeString(mProvider); parcel.writeLong(mTime); parcel.writeLong(mElapsedRealtimeNanos); - parcel.writeLong(mElapsedRealtimeUncertaintyNanos); parcel.writeByte(mFieldsMask); parcel.writeDouble(mLatitude); parcel.writeDouble(mLongitude); diff --git a/media/apex/java/android/media/CallbackDataSourceDesc.java b/media/apex/java/android/media/CallbackDataSourceDesc.java index cd364145e8a4..9209ca94897f 100644 --- a/media/apex/java/android/media/CallbackDataSourceDesc.java +++ b/media/apex/java/android/media/CallbackDataSourceDesc.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.NonNull; +import android.annotation.Nullable; /** * Structure of data source descriptor for sources using callback. @@ -37,7 +38,7 @@ public class CallbackDataSourceDesc extends DataSourceDesc { * Return the DataSourceCallback of this data source. * @return the DataSourceCallback of this data source */ - public DataSourceCallback getDataSourceCallback() { + public @NonNull DataSourceCallback getDataSourceCallback() { return mDataSourceCallback; } @@ -70,7 +71,7 @@ public class CallbackDataSourceDesc extends DataSourceDesc { * @param dsd the {@link CallbackDataSourceDesc} object whose data will be reused * in the new Builder. */ - public Builder(CallbackDataSourceDesc dsd) { + public Builder(@Nullable CallbackDataSourceDesc dsd) { super(dsd); if (dsd == null) { return; // use default @@ -86,6 +87,11 @@ public class CallbackDataSourceDesc extends DataSourceDesc { * @return a new {@link CallbackDataSourceDesc} object */ public @NonNull CallbackDataSourceDesc build() { + if (mDataSourceCallback == null) { + throw new IllegalStateException( + "DataSourceCallback should not be null"); + } + CallbackDataSourceDesc dsd = new CallbackDataSourceDesc(); super.build(dsd); dsd.mDataSourceCallback = mDataSourceCallback; diff --git a/media/apex/java/android/media/DataSourceCallback.java b/media/apex/java/android/media/DataSourceCallback.java index 1afcd2075ba4..6515bd6a2c09 100644 --- a/media/apex/java/android/media/DataSourceCallback.java +++ b/media/apex/java/android/media/DataSourceCallback.java @@ -17,6 +17,8 @@ package android.media; +import android.annotation.NonNull; + import java.io.Closeable; import java.io.IOException; @@ -49,7 +51,7 @@ public abstract class DataSourceCallback implements Closeable { * @throws IOException on fatal errors. * @return the number of bytes read, or -1 if end of stream is reached. */ - public abstract int readAt(long position, byte[] buffer, int offset, int size) + public abstract int readAt(long position, @NonNull byte[] buffer, int offset, int size) throws IOException; /** diff --git a/media/apex/java/android/media/DataSourceDesc.java b/media/apex/java/android/media/DataSourceDesc.java index 7fc6f794cff8..e6fd120b6d5b 100644 --- a/media/apex/java/android/media/DataSourceDesc.java +++ b/media/apex/java/android/media/DataSourceDesc.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.NonNull; +import android.annotation.Nullable; /** * Base class of data source descriptor. @@ -64,7 +65,7 @@ public class DataSourceDesc { * Return the media Id of data source. * @return the media Id of data source */ - public String getMediaId() { + public @Nullable String getMediaId() { return mMediaId; } @@ -149,7 +150,7 @@ public class DataSourceDesc { * @param mediaId the media Id of this data source * @return the same Builder instance. */ - public @NonNull T setMediaId(String mediaId) { + public @NonNull T setMediaId(@Nullable String mediaId) { mMediaId = mediaId; return (T) this; } diff --git a/media/apex/java/android/media/FileDataSourceDesc.java b/media/apex/java/android/media/FileDataSourceDesc.java index e29bd006c00a..4b703670abf1 100644 --- a/media/apex/java/android/media/FileDataSourceDesc.java +++ b/media/apex/java/android/media/FileDataSourceDesc.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -106,7 +107,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * Return the ParcelFileDescriptor of this data source. * @return the ParcelFileDescriptor of this data source */ - public ParcelFileDescriptor getParcelFileDescriptor() { + public @NonNull ParcelFileDescriptor getParcelFileDescriptor() { return mPFD; } @@ -159,7 +160,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * @param dsd the {@link FileDataSourceDesc} object whose data will be reused * in the new Builder. */ - public Builder(FileDataSourceDesc dsd) { + public Builder(@Nullable FileDataSourceDesc dsd) { super(dsd); if (dsd == null) { return; // use default diff --git a/media/apex/java/android/media/MediaItem2.java b/media/apex/java/android/media/MediaItem2.java index fc0f08ead46e..ff0d43e41350 100644 --- a/media/apex/java/android/media/MediaItem2.java +++ b/media/apex/java/android/media/MediaItem2.java @@ -245,7 +245,7 @@ public final class MediaItem2 implements Parcelable { /** * Builder for {@link MediaItem2}. */ - public static class Builder { + public static final class Builder { @SuppressWarnings("WeakerAccess") /* synthetic access */ MediaMetadata mMetadata; @SuppressWarnings("WeakerAccess") /* synthetic access */ diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java index ef30172213bb..f6b2031bc456 100644 --- a/media/apex/java/android/media/MediaPlayer2.java +++ b/media/apex/java/android/media/MediaPlayer2.java @@ -344,7 +344,7 @@ public class MediaPlayer2 implements AutoCloseable * to free the resources. If not released, too many MediaPlayer2 instances may * result in an exception.</p> */ - public MediaPlayer2(Context context) { + public MediaPlayer2(@NonNull Context context) { mGuard.open("close"); mContext = context; @@ -488,7 +488,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object play() { + public @NonNull Object play() { return addTask(new Task(CALL_COMPLETED_PLAY, false) { @Override void process() { @@ -508,7 +508,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object prepare() { + public @NonNull Object prepare() { return addTask(new Task(CALL_COMPLETED_PREPARE, true) { @Override void process() { @@ -524,7 +524,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object pause() { + public @NonNull Object pause() { return addTask(new Task(CALL_COMPLETED_PAUSE, false) { @Override void process() { @@ -542,7 +542,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object skipToNext() { + public @NonNull Object skipToNext() { return addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) { @Override void process() { @@ -700,7 +700,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setAudioAttributes(@NonNull AudioAttributes attributes) { + public @NonNull Object setAudioAttributes(@NonNull AudioAttributes attributes) { return addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) { @Override void process() { @@ -735,7 +735,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setDataSource(@NonNull DataSourceDesc dsd) { + public @NonNull Object setDataSource(@NonNull DataSourceDesc dsd) { return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) { @Override void process() throws IOException { @@ -768,7 +768,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setNextDataSource(@NonNull DataSourceDesc dsd) { + public @NonNull Object setNextDataSource(@NonNull DataSourceDesc dsd) { return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) { @Override void process() { @@ -791,7 +791,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setNextDataSources(@NonNull List<DataSourceDesc> dsds) { + public @NonNull Object setNextDataSources(@NonNull List<DataSourceDesc> dsds) { return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) { @Override void process() { @@ -853,7 +853,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object clearNextDataSources() { + public @NonNull Object clearNextDataSources() { return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) { @Override void process() { @@ -1194,7 +1194,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object loopCurrent(boolean loop) { + public @NonNull Object loopCurrent(boolean loop) { return addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) { @Override void process() { @@ -1216,7 +1216,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setPlayerVolume(float volume) { + public @NonNull Object setPlayerVolume(float volume) { return addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) { @Override void process() { @@ -1257,7 +1257,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object notifyWhenCommandLabelReached(@NonNull Object label) { + public @NonNull Object notifyWhenCommandLabelReached(@NonNull Object label) { return addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) { @Override void process() { @@ -1285,7 +1285,7 @@ public class MediaPlayer2 implements AutoCloseable * @param sh the SurfaceHolder to use for video display * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ - public Object setDisplay(SurfaceHolder sh) { + public @NonNull Object setDisplay(@Nullable SurfaceHolder sh) { return addTask(new Task(CALL_COMPLETED_SET_DISPLAY, false) { @Override void process() { @@ -1321,7 +1321,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setSurface(Surface surface) { + public @NonNull Object setSurface(@Nullable Surface surface) { return addTask(new Task(CALL_COMPLETED_SET_SURFACE, false) { @Override void process() { @@ -1355,7 +1355,7 @@ public class MediaPlayer2 implements AutoCloseable * @see android.os.PowerManager */ // This is an asynchronous call. - public Object setWakeLock(@NonNull PowerManager.WakeLock wakeLock) { + public @NonNull Object setWakeLock(@NonNull PowerManager.WakeLock wakeLock) { return addTask(new Task(CALL_COMPLETED_SET_WAKE_LOCK, false) { @Override void process() { @@ -1390,7 +1390,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setScreenOnWhilePlaying(boolean screenOn) { + public @NonNull Object setScreenOnWhilePlaying(boolean screenOn) { return addTask(new Task(CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING, false) { @Override void process() { @@ -1466,7 +1466,7 @@ public class MediaPlayer2 implements AutoCloseable */ // This is a synchronous call. @Override - public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { + public boolean setPreferredDevice(@Nullable AudioDeviceInfo deviceInfo) { boolean status = native_setPreferredDevice(deviceInfo); if (status) { synchronized (this) { @@ -1483,7 +1483,7 @@ public class MediaPlayer2 implements AutoCloseable * is not guaranteed to correspond to the actual device being used for playback. */ @Override - public AudioDeviceInfo getPreferredDevice() { + public @Nullable AudioDeviceInfo getPreferredDevice() { synchronized (this) { return mPreferredDevice; } @@ -1496,7 +1496,7 @@ public class MediaPlayer2 implements AutoCloseable * selected device when the player was last active. */ @Override - public native AudioDeviceInfo getRoutedDevice(); + public @Nullable native AudioDeviceInfo getRoutedDevice(); /** * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing @@ -1508,8 +1508,8 @@ public class MediaPlayer2 implements AutoCloseable */ // This is a synchronous call. @Override - public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, - Handler handler) { + public void addOnRoutingChangedListener(@NonNull AudioRouting.OnRoutingChangedListener listener, + @Nullable Handler handler) { if (listener == null) { throw new IllegalArgumentException("addOnRoutingChangedListener: listener is NULL"); } @@ -1527,7 +1527,8 @@ public class MediaPlayer2 implements AutoCloseable */ // This is a synchronous call. @Override - public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { + public void removeOnRoutingChangedListener( + @NonNull AudioRouting.OnRoutingChangedListener listener) { if (listener == null) { throw new IllegalArgumentException("removeOnRoutingChangedListener: listener is NULL"); } @@ -1547,7 +1548,7 @@ public class MediaPlayer2 implements AutoCloseable * notification {@code EventCallback.onVideoSizeChanged} when the size * is available. */ - public Size getVideoSize() { + public @NonNull Size getVideoSize() { return mVideoSize; } @@ -1560,7 +1561,7 @@ public class MediaPlayer2 implements AutoCloseable * * Additional vendor-specific fields may also be present in the return value. */ - public PersistableBundle getMetrics() { + public @Nullable PersistableBundle getMetrics() { PersistableBundle bundle = native_getMetrics(); return bundle; } @@ -1592,7 +1593,7 @@ public class MediaPlayer2 implements AutoCloseable */ // TODO: make it public when ready // This is an asynchronous call. - Object setBufferingParams(@NonNull BufferingParams params) { + @NonNull Object setBufferingParams(@NonNull BufferingParams params) { return addTask(new Task(CALL_COMPLETED_SET_BUFFERING_PARAMS, false) { @Override void process() { @@ -1614,7 +1615,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setPlaybackParams(@NonNull PlaybackParams params) { + public @NonNull Object setPlaybackParams(@NonNull PlaybackParams params) { return addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) { @Override void process() { @@ -1642,7 +1643,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setSyncParams(@NonNull SyncParams params) { + public @NonNull Object setSyncParams(@NonNull SyncParams params) { return addTask(new Task(CALL_COMPLETED_SET_SYNC_PARAMS, false) { @Override void process() { @@ -1671,7 +1672,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object seekTo(long msec) { + public @NonNull Object seekTo(long msec) { return seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */); } @@ -1745,7 +1746,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object seekTo(long msec, @SeekMode int mode) { + public @NonNull Object seekTo(long msec, @SeekMode int mode) { return addTask(new Task(CALL_COMPLETED_SEEK_TO, true) { @Override void process() { @@ -1846,7 +1847,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setAudioSessionId(int sessionId) { + public @NonNull Object setAudioSessionId(int sessionId) { final AudioTrack dummyAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2, AudioTrack.MODE_STATIC, sessionId); @@ -1887,7 +1888,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object attachAuxEffect(int effectId) { + public @NonNull Object attachAuxEffect(int effectId) { return addTask(new Task(CALL_COMPLETED_ATTACH_AUX_EFFECT, false) { @Override void process() { @@ -1912,7 +1913,7 @@ public class MediaPlayer2 implements AutoCloseable * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. - public Object setAuxEffectSendLevel(float level) { + public @NonNull Object setAuxEffectSendLevel(float level) { return addTask(new Task(CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL, false) { @Override void process() { @@ -1984,7 +1985,7 @@ public class MediaPlayer2 implements AutoCloseable * When the language is unknown or could not be determined, * ISO-639-2 language code, "und", is returned. */ - public String getLanguage() { + public @Nullable String getLanguage() { String language = mFormat.getString(MediaFormat.KEY_LANGUAGE); return language == null ? "und" : language; } @@ -1993,7 +1994,7 @@ public class MediaPlayer2 implements AutoCloseable * Gets the {@link MediaFormat} of the track. If the format is * unknown or could not be determined, null is returned. */ - public MediaFormat getFormat() { + public @Nullable MediaFormat getFormat() { if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) { return mFormat; @@ -2201,7 +2202,7 @@ public class MediaPlayer2 implements AutoCloseable * @see MediaPlayer2#getTrackInfo() */ // This is an asynchronous call. - public Object selectTrack(int index) { + public @NonNull Object selectTrack(int index) { return selectTrack(getCurrentDataSource(), index); } @@ -2235,7 +2236,7 @@ public class MediaPlayer2 implements AutoCloseable * @see MediaPlayer2#getTrackInfo(DataSourceDesc) */ // This is an asynchronous call. - public Object selectTrack(@NonNull DataSourceDesc dsd, int index) { + public @NonNull Object selectTrack(@NonNull DataSourceDesc dsd, int index) { return addTask(new Task(CALL_COMPLETED_SELECT_TRACK, false) { @Override void process() { @@ -2257,7 +2258,7 @@ public class MediaPlayer2 implements AutoCloseable * @see MediaPlayer2#getTrackInfo() */ // This is an asynchronous call. - public Object deselectTrack(int index) { + public @NonNull Object deselectTrack(int index) { return deselectTrack(getCurrentDataSource(), index); } @@ -2277,7 +2278,7 @@ public class MediaPlayer2 implements AutoCloseable * @see MediaPlayer2#getTrackInfo(DataSourceDesc) */ // This is an asynchronous call. - public Object deselectTrack(@NonNull DataSourceDesc dsd, int index) { + public @NonNull Object deselectTrack(@NonNull DataSourceDesc dsd, int index) { return addTask(new Task(CALL_COMPLETED_DESELECT_TRACK, false) { @Override void process() { @@ -2928,7 +2929,7 @@ public class MediaPlayer2 implements AutoCloseable * @param eventCallback the callback to be unregistered */ // This is a synchronous call. - public void unregisterEventCallback(EventCallback eventCallback) { + public void unregisterEventCallback(@NonNull EventCallback eventCallback) { synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { if (cb.second == eventCallback) { @@ -3850,7 +3851,7 @@ public class MediaPlayer2 implements AutoCloseable */ // This is an asynchronous call. @TestApi - public Object prepareDrm(@NonNull DataSourceDesc dsd, @NonNull UUID uuid) { + public @NonNull Object prepareDrm(@NonNull DataSourceDesc dsd, @NonNull UUID uuid) { return addTask(newPrepareDrmTask(dsd, uuid)); } diff --git a/media/apex/java/android/media/UriDataSourceDesc.java b/media/apex/java/android/media/UriDataSourceDesc.java index 4eb9e8d3376f..c0b3c825323c 100644 --- a/media/apex/java/android/media/UriDataSourceDesc.java +++ b/media/apex/java/android/media/UriDataSourceDesc.java @@ -51,7 +51,7 @@ public class UriDataSourceDesc extends DataSourceDesc { * Return the Uri of this data source. * @return the Uri of this data source */ - public Uri getUri() { + public @NonNull Uri getUri() { return mUri; } @@ -59,7 +59,7 @@ public class UriDataSourceDesc extends DataSourceDesc { * Return the Uri headers of this data source. * @return the Uri headers of this data source */ - public Map<String, String> getHeaders() { + public @Nullable Map<String, String> getHeaders() { if (mHeader == null) { return null; } @@ -70,7 +70,7 @@ public class UriDataSourceDesc extends DataSourceDesc { * Return the Uri cookies of this data source. * @return the Uri cookies of this data source */ - public List<HttpCookie> getCookies() { + public @Nullable List<HttpCookie> getCookies() { if (mCookies == null) { return null; } @@ -81,7 +81,7 @@ public class UriDataSourceDesc extends DataSourceDesc { * Return the Context used for resolving the Uri of this data source. * @return the Context used for resolving the Uri of this data source */ - public Context getContext() { + public @NonNull Context getContext() { return mContext; } @@ -117,7 +117,7 @@ public class UriDataSourceDesc extends DataSourceDesc { * @param dsd the {@link UriDataSourceDesc} object whose data will be reused * in the new Builder. */ - public Builder(UriDataSourceDesc dsd) { + public Builder(@Nullable UriDataSourceDesc dsd) { super(dsd); if (dsd == null) { return; // use default @@ -136,6 +136,11 @@ public class UriDataSourceDesc extends DataSourceDesc { * @return a new {@link UriDataSourceDesc} object */ public @NonNull UriDataSourceDesc build() { + if (mUri == null || mContext == null) { + throw new IllegalStateException( + "Uri and Context should not be null"); + } + UriDataSourceDesc dsd = new UriDataSourceDesc(); super.build(dsd); dsd.mUri = mUri; diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 46d4204b4d5e..aed8e4ede1c4 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -630,7 +630,7 @@ public final class AudioAttributes implements Parcelable { * true to allow apps to capture the audio * @return the same Builder instance */ - public Builder setAllowCapture(boolean allowCapture) { + public @NonNull Builder setAllowCapture(boolean allowCapture) { if (allowCapture) { mFlags &= ~FLAG_NO_CAPTURE; } else { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 15f9b47ede09..669baeadad65 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -4068,6 +4068,10 @@ public class AudioManager { /** * Indicate Hearing Aid connection state change and eventually suppress * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. + * This operation is asynchronous but its execution will still be sequentially scheduled + * relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( + * * BluetoothDevice, int, int, boolean, int)} and + * and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}. * @param device Bluetooth device connected/disconnected * @param state new connection state (BluetoothProfile.STATE_xxx) * @param musicDevice Default get system volume for the connecting device. @@ -4075,27 +4079,27 @@ public class AudioManager { * {@link android.bluetooth.BluetoothProfile.HEARING_AID}) * @param suppressNoisyIntent if true the * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. - * @return a delay in ms that the caller should wait before broadcasting - * BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED intent. * {@hide} */ - public int setBluetoothHearingAidDeviceConnectionState( + public void setBluetoothHearingAidDeviceConnectionState( BluetoothDevice device, int state, boolean suppressNoisyIntent, int musicDevice) { final IAudioService service = getService(); - int delay = 0; try { - delay = service.setBluetoothHearingAidDeviceConnectionState(device, + service.setBluetoothHearingAidDeviceConnectionState(device, state, suppressNoisyIntent, musicDevice); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - return delay; } /** * Indicate A2DP source or sink connection state change and eventually suppress * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. + * This operation is asynchronous but its execution will still be sequentially scheduled + * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, + * int, boolean, int)} and + * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}. * @param device Bluetooth device connected/disconnected * @param state new connection state, {@link BluetoothProfile#STATE_CONNECTED} * or {@link BluetoothProfile#STATE_DISCONNECTED} @@ -4105,26 +4109,27 @@ public class AudioManager { * {@link android.bluetooth.BluetoothProfile.A2DP_SINK}) * @param suppressNoisyIntent if true the * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. - * @return a delay in ms that the caller should wait before broadcasting - * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent. * {@hide} */ - public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( + public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { final IAudioService service = getService(); - int delay = 0; try { - delay = service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, + service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, state, profile, suppressNoisyIntent, a2dpVolume); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - return delay; } /** * Indicate A2DP device configuration has changed. + * This operation is asynchronous but its execution will still be sequentially scheduled + * relative to calls to + * {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int, + * boolean, int)} and + * {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)} * @param device Bluetooth device whose configuration has changed. * {@hide} */ diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java index 9a16aea1e052..333cd2d4f0cf 100644 --- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java +++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java @@ -72,7 +72,7 @@ public final class AudioPlaybackCaptureConfiguration { * * @param audioFormat The format in which to capture the audio. */ - AudioMix createAudioMix(AudioFormat audioFormat) { + @NonNull AudioMix createAudioMix(@NonNull AudioFormat audioFormat) { return new AudioMix.Builder(mAudioMixingRule) .setFormat(audioFormat) .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER) @@ -123,7 +123,7 @@ public final class AudioPlaybackCaptureConfiguration { * @throws IllegalStateException if called in conjunction with * {@link #excludeUsage(AudioAttributes)}. */ - public Builder addMatchingUsage(@NonNull AudioAttributes audioAttributes) { + public @NonNull Builder addMatchingUsage(@NonNull AudioAttributes audioAttributes) { Preconditions.checkNotNull(audioAttributes); Preconditions.checkState( mUsageMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES); @@ -141,7 +141,7 @@ public final class AudioPlaybackCaptureConfiguration { * * @throws IllegalStateException if called in conjunction with {@link #excludeUid(int)}. */ - public Builder addMatchingUid(int uid) { + public @NonNull Builder addMatchingUid(int uid) { Preconditions.checkState( mUidMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES); mAudioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_UID, uid); @@ -158,7 +158,7 @@ public final class AudioPlaybackCaptureConfiguration { * @throws IllegalStateException if called in conjunction with * {@link #addMatchingUsage(AudioAttributes)}. */ - public Builder excludeUsage(@NonNull AudioAttributes audioAttributes) { + public @NonNull Builder excludeUsage(@NonNull AudioAttributes audioAttributes) { Preconditions.checkNotNull(audioAttributes); Preconditions.checkState( mUsageMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES); @@ -176,7 +176,7 @@ public final class AudioPlaybackCaptureConfiguration { * * @throws IllegalStateException if called in conjunction with {@link #addMatchingUid(int)}. */ - public Builder excludeUid(int uid) { + public @NonNull Builder excludeUid(int uid) { Preconditions.checkState( mUidMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES); mAudioMixingRuleBuilder.excludeMixRule(AudioMixingRule.RULE_MATCH_UID, uid); @@ -189,7 +189,7 @@ public final class AudioPlaybackCaptureConfiguration { * * @throws UnsupportedOperationException if the parameters set are incompatible. */ - public AudioPlaybackCaptureConfiguration build() { + public @NonNull AudioPlaybackCaptureConfiguration build() { return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build(), mProjection); } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 3d5120f86db3..28937a65ad0d 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -618,7 +618,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, * @throws IllegalStateException if called in conjunction with {@link #setAudioSource(int)}. * @throws NullPointerException if {@code config} is null. */ - public Builder setAudioPlaybackCaptureConfig( + public @NonNull Builder setAudioPlaybackCaptureConfig( @NonNull AudioPlaybackCaptureConfiguration config) { Preconditions.checkNotNull( config, "Illegal null AudioPlaybackCaptureConfiguration argument"); @@ -647,7 +647,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, return this; } - private AudioRecord buildAudioPlaybackCaptureRecord() { + private @NonNull AudioRecord buildAudioPlaybackCaptureRecord() { AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat); MediaProjection projection = mAudioPlaybackCaptureConfiguration.getMediaProjection(); AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null) diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java index 8bdb8a63f470..d9be0a593e4b 100644 --- a/media/java/android/media/HwAudioSource.java +++ b/media/java/android/media/HwAudioSource.java @@ -165,7 +165,7 @@ public class HwAudioSource extends PlayerBase { * If the audio attributes are not set with {@link #setAudioAttributes(AudioAttributes)}, * attributes comprising {@link AudioAttributes#USAGE_MEDIA} will be used. */ - public static class Builder { + public static final class Builder { private AudioAttributes mAudioAttributes; private AudioDeviceInfo mAudioDeviceInfo; diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 1b82fcc48bf8..02856678879e 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -228,10 +228,10 @@ interface IAudioService { oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio); - int setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device, + void setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device, int state, boolean suppressNoisyIntent, int musicDevice); - int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device, + void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume); oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult, diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java index 03e454c1e962..da3362a019b9 100644 --- a/media/java/android/media/MediaTimestamp.java +++ b/media/java/android/media/MediaTimestamp.java @@ -134,7 +134,7 @@ public final class MediaTimestamp * @hide */ @SystemApi - public static class Builder { + public static final class Builder { long mMediaTimeUs; long mNanoTime; float mClockRate = 1.0f; diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index fbe51525c29c..b302b06df782 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -571,13 +571,12 @@ public abstract class PlayerBase { // Utilities /** + * @hide * Use to generate warning or exception in legacy code paths that allowed passing stream types * to qualify audio playback. * @param streamType the stream type to check * @throws IllegalArgumentException - * @deprecated This method is not intended to be used by applications. */ - @java.lang.Deprecated public static void deprecateStreamTypeForPlayback(int streamType, @NonNull String className, @NonNull String opName) throws IllegalArgumentException { // STREAM_ACCESSIBILITY was introduced at the same time the use of stream types diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java index 852babe1ecea..31622a9d467c 100644 --- a/media/java/android/media/SubtitleData.java +++ b/media/java/android/media/SubtitleData.java @@ -155,7 +155,7 @@ public final class SubtitleData * @hide */ @SystemApi - public static class Builder { + public static final class Builder { private int mTrackIndex; private long mStartTimeUs; private long mDurationUs; diff --git a/media/java/android/media/TimedMetaData.java b/media/java/android/media/TimedMetaData.java index 2a8988855168..990760cf32ae 100644 --- a/media/java/android/media/TimedMetaData.java +++ b/media/java/android/media/TimedMetaData.java @@ -104,7 +104,7 @@ public final class TimedMetaData { * @hide */ @SystemApi - public static class Builder { + public static final class Builder { private long mTimestampUs; private byte[] mMetaData = new byte[0]; diff --git a/media/java/android/media/audiopolicy/AudioProductStrategies.java b/media/java/android/media/audiopolicy/AudioProductStrategies.java index 98b6d97ec992..c305b683f136 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategies.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategies.java @@ -85,7 +85,7 @@ public final class AudioProductStrategies implements Iterable<AudioProductStrate * Returns an {@link Iterator} */ @Override - public Iterator<AudioProductStrategy> iterator() { + public @NonNull Iterator<AudioProductStrategy> iterator() { return mAudioProductStrategyList.iterator(); } diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroup.java b/media/java/android/media/audiopolicy/AudioVolumeGroup.java index 0b4ba937ad29..b60947f13c1f 100644 --- a/media/java/android/media/audiopolicy/AudioVolumeGroup.java +++ b/media/java/android/media/audiopolicy/AudioVolumeGroup.java @@ -77,7 +77,7 @@ public final class AudioVolumeGroup implements Parcelable { /** * @return List of {@link AudioAttributes} involved in this {@link AudioVolumeGroup}. */ - public List<AudioAttributes> getAudioAttributes() { + public @NonNull List<AudioAttributes> getAudioAttributes() { return Arrays.asList(mAudioAttributes); } diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroups.java b/media/java/android/media/audiopolicy/AudioVolumeGroups.java index 301bec7a10c4..2e56f846e574 100644 --- a/media/java/android/media/audiopolicy/AudioVolumeGroups.java +++ b/media/java/android/media/audiopolicy/AudioVolumeGroups.java @@ -70,7 +70,7 @@ public final class AudioVolumeGroups implements Iterable<AudioVolumeGroup>, Parc * Returns an {@link Iterator} */ @Override - public Iterator<AudioVolumeGroup> iterator() { + public @NonNull Iterator<AudioVolumeGroup> iterator() { return mAudioVolumeGroupList.iterator(); } diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk index fb473f0581c9..167d255af74c 100644 --- a/media/tests/MediaFrameworkTest/Android.mk +++ b/media/tests/MediaFrameworkTest/Android.mk @@ -9,7 +9,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_STATIC_JAVA_LIBRARIES := \ mockito-target-minus-junit4 \ - android-support-test \ + androidx.test.rules \ android-ex-camera2 LOCAL_PACKAGE_NAME := mediaframeworktest diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml index e50a3757d14f..fb2d630faaf6 100644 --- a/media/tests/MediaFrameworkTest/AndroidManifest.xml +++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml @@ -86,7 +86,7 @@ android:label="MediaFramework integration tests InstrumentationRunner"> </instrumentation> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.mediaframeworktest" android:label="media framework tests"> </instrumentation> diff --git a/media/tests/MediaFrameworkTest/AndroidTest.xml b/media/tests/MediaFrameworkTest/AndroidTest.xml index 204959ff2749..132028ce98dc 100644 --- a/media/tests/MediaFrameworkTest/AndroidTest.xml +++ b/media/tests/MediaFrameworkTest/AndroidTest.xml @@ -21,7 +21,7 @@ <option name="test-tag" value="MediaFrameworkTest" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.mediaframeworktest" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> </test> </configuration> diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index d8c975f44c6a..87a59df19e8e 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -309,6 +309,10 @@ public class CameraBinderTest extends AndroidTestCase { Log.v(TAG, String.format("Camera %s has torch status changed to 0x%x", cameraId, status)); } + @Override + public void onCameraAccessPrioritiesChanged() { + Log.v(TAG, "Camera access permission change"); + } } /** diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java index feac63d40710..701454c32e4b 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java @@ -28,7 +28,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.mtp.MtpConstants; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.runner.AndroidJUnit4; import libcore.net.MimeUtils; diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp index a71977f8cc6c..bc614e9fc14c 100644 --- a/packages/CaptivePortalLogin/Android.bp +++ b/packages/CaptivePortalLogin/Android.bp @@ -18,6 +18,7 @@ android_app { name: "CaptivePortalLogin", srcs: ["src/**/*.java"], sdk_version: "system_current", + min_sdk_version: "28", certificate: "networkstack", static_libs: [ "androidx.legacy_legacy-support-v4", diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml index a5f3b88fef0a..44e0a659212a 100644 --- a/packages/CaptivePortalLogin/AndroidManifest.xml +++ b/packages/CaptivePortalLogin/AndroidManifest.xml @@ -18,7 +18,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.captiveportallogin" - android:versionCode="10" + android:versionCode="11" android:versionName="Q-initial"> <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" /> diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java index 7755cbc9ca3b..719417e96015 100644 --- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java +++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java @@ -114,6 +114,7 @@ public class DynamicAndroidInstallationService extends Service private NotificationManager mNM; private long mSystemSize; + private long mUserdataSize; private long mInstalledSize; private boolean mJustCancelledByUser; @@ -220,9 +221,11 @@ public class DynamicAndroidInstallationService extends Service String url = intent.getStringExtra(DynamicAndroidClient.KEY_SYSTEM_URL); mSystemSize = intent.getLongExtra(DynamicAndroidClient.KEY_SYSTEM_SIZE, 0); - long userdata = intent.getLongExtra(DynamicAndroidClient.KEY_USERDATA_SIZE, 0); + mUserdataSize = intent.getLongExtra(DynamicAndroidClient.KEY_USERDATA_SIZE, 0); + + mInstallTask = new InstallationAsyncTask( + url, mSystemSize, mUserdataSize, mDynAndroid, this); - mInstallTask = new InstallationAsyncTask(url, mSystemSize, userdata, mDynAndroid, this); mInstallTask.execute(); // start fore ground @@ -332,8 +335,8 @@ public class DynamicAndroidInstallationService extends Service case STATUS_IN_PROGRESS: builder.setContentText(getString(R.string.notification_install_inprogress)); - int max = (int) Math.max(mSystemSize >> 20, 1); - int progress = (int) mInstalledSize >> 20; + int max = (int) Math.max((mSystemSize + mUserdataSize) >> 20, 1); + int progress = (int) (mInstalledSize >> 20); builder.setProgress(max, progress, false); diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java index 3c759e948b4e..03fc7739fcce 100644 --- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java +++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java @@ -16,6 +16,7 @@ package com.android.dynandroid; +import android.gsi.GsiProgress; import android.os.AsyncTask; import android.os.DynamicAndroidManager; import android.util.Log; @@ -63,8 +64,6 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Integer> { private final InstallStatusListener mListener; private DynamicAndroidManager.Session mInstallationSession; - private long mInstalledSize; - private long mReportedInstalledSize; private int mResult = NO_RESULT; private InputStream mStream; @@ -89,8 +88,40 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Integer> { Log.d(TAG, "Start doInBackground(), URL: " + mUrl); try { - // call start in background - mInstallationSession = mDynamicAndroid.startInstallation(mSystemSize, mUserdataSize); + long installedSize = 0; + long reportedInstalledSize = 0; + + long minStepToReport = (mSystemSize + mUserdataSize) / 100; + + // init input stream before calling startInstallation(), which takes 90 seconds. + initInputStream(); + + Thread thread = new Thread(() -> { + mInstallationSession = + mDynamicAndroid.startInstallation(mSystemSize, mUserdataSize); + }); + + + thread.start(); + + while (thread.isAlive()) { + if (isCancelled()) { + boolean aborted = mDynamicAndroid.abort(); + Log.d(TAG, "Called DynamicAndroidManager.abort(), result = " + aborted); + return RESULT_OK; + } + + GsiProgress progress = mDynamicAndroid.getInstallationProgress(); + installedSize = progress.bytes_processed; + + if (installedSize > reportedInstalledSize + minStepToReport) { + publishProgress(installedSize); + reportedInstalledSize = installedSize; + } + + Thread.sleep(10); + } + if (mInstallationSession == null) { Log.e(TAG, "Failed to start installation with requested size: " @@ -99,12 +130,11 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Integer> { return RESULT_ERROR_IO; } - initInputStream(); + installedSize = mUserdataSize; byte[] bytes = new byte[READ_BUFFER_SIZE]; int numBytesRead; - long minStepToReport = mSystemSize / 100; Log.d(TAG, "Start installation loop"); while ((numBytesRead = mStream.read(bytes, 0, READ_BUFFER_SIZE)) != -1) { @@ -119,11 +149,11 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Integer> { throw new IOException("Failed write() to DynamicAndroid"); } - mInstalledSize += numBytesRead; + installedSize += numBytesRead; - if (mInstalledSize > mReportedInstalledSize + minStepToReport) { - publishProgress(mInstalledSize); - mReportedInstalledSize = mInstalledSize; + if (installedSize > reportedInstalledSize + minStepToReport) { + publishProgress(installedSize); + reportedInstalledSize = installedSize; } } diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index 5f1f26d88171..f210840b976f 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -36,6 +36,7 @@ java_library { android_app { name: "NetworkStack", sdk_version: "system_current", + min_sdk_version: "28", certificate: "networkstack", privileged: true, static_libs: [ diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml index 740c573eb914..003f1e59d743 100644 --- a/packages/NetworkStack/AndroidManifest.xml +++ b/packages/NetworkStack/AndroidManifest.xml @@ -19,7 +19,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.networkstack" android:sharedUserId="android.uid.networkstack" - android:versionCode="10" + android:versionCode="11" android:versionName="Q-initial"> <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" /> <uses-permission android:name="android.permission.INTERNET" /> diff --git a/packages/NetworkStackPermissionStub/Android.bp b/packages/NetworkStackPermissionStub/Android.bp index dd70cf56b51b..8cee92e5fe6d 100644 --- a/packages/NetworkStackPermissionStub/Android.bp +++ b/packages/NetworkStackPermissionStub/Android.bp @@ -21,6 +21,7 @@ android_app { // a classes.dex. srcs: ["src/**/*.java"], platform_apis: true, + min_sdk_version: "28", certificate: "networkstack", privileged: true, manifest: "AndroidManifest.xml", diff --git a/packages/NetworkStackPermissionStub/AndroidManifest.xml b/packages/NetworkStackPermissionStub/AndroidManifest.xml index 62bf3de3fb95..e83f0503d280 100644 --- a/packages/NetworkStackPermissionStub/AndroidManifest.xml +++ b/packages/NetworkStackPermissionStub/AndroidManifest.xml @@ -19,7 +19,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.networkstack.permissionstub" android:sharedUserId="android.uid.networkstack" - android:versionCode="10" + android:versionCode="11" android:versionName="Q-initial"> <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" /> <!-- diff --git a/packages/SystemUI/res/drawable/ic_volume_remote.xml b/packages/SettingsLib/res/drawable/ic_volume_remote.xml index fe396d9cc496..fe396d9cc496 100644 --- a/packages/SystemUI/res/drawable/ic_volume_remote.xml +++ b/packages/SettingsLib/res/drawable/ic_volume_remote.xml diff --git a/packages/SystemUI/res/drawable/ic_volume_remote_mute.xml b/packages/SettingsLib/res/drawable/ic_volume_remote_mute.xml index 2e0512244ddf..2e0512244ddf 100644 --- a/packages/SystemUI/res/drawable/ic_volume_remote_mute.xml +++ b/packages/SettingsLib/res/drawable/ic_volume_remote_mute.xml diff --git a/core/java/android/service/textclassifier/ITextLinksCallback.aidl b/packages/SettingsLib/src/com/android/settingslib/volume/D.java index a9e0dde56773..7e0654d72b47 100644 --- a/core/java/android/service/textclassifier/ITextLinksCallback.aidl +++ b/packages/SettingsLib/src/com/android/settingslib/volume/D.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * 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. @@ -14,15 +14,10 @@ * limitations under the License. */ -package android.service.textclassifier; +package com.android.settingslib.volume; -import android.view.textclassifier.TextLinks; +import android.util.Log; -/** - * Callback for a TextLinks request. - * @hide - */ -oneway interface ITextLinksCallback { - void onSuccess(in TextLinks links); - void onFailure(); -}
\ No newline at end of file +class D { + public static boolean BUG = Log.isLoggable("volume", Log.DEBUG); +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java index 8b00eee29c6e..4ed115405f57 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java +++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.volume; +package com.android.settingslib.volume; import android.app.PendingIntent; import android.content.Context; @@ -27,7 +27,6 @@ import android.media.IRemoteVolumeController; import android.media.MediaMetadata; import android.media.session.MediaController; import android.media.session.MediaController.PlaybackInfo; -import android.media.session.MediaSession; import android.media.session.MediaSession.QueueItem; import android.media.session.MediaSession.Token; import android.media.session.MediaSessionManager; @@ -41,7 +40,6 @@ import android.os.RemoteException; import android.util.Log; import java.io.PrintWriter; -import java.io.StringWriter; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -73,16 +71,24 @@ public class MediaSessions { mCallbacks = callbacks; } + /** + * Dump to {@code writer} + */ public void dump(PrintWriter writer) { writer.println(getClass().getSimpleName() + " state:"); - writer.print(" mInit: "); writer.println(mInit); - writer.print(" mRecords.size: "); writer.println(mRecords.size()); + writer.print(" mInit: "); + writer.println(mInit); + writer.print(" mRecords.size: "); + writer.println(mRecords.size()); int i = 0; for (MediaControllerRecord r : mRecords.values()) { dump(++i, writer, r.controller); } } + /** + * init MediaSessions + */ public void init() { if (D.BUG) Log.d(TAG, "init"); // will throw if no permission @@ -97,12 +103,18 @@ public class MediaSessions { mHandler.sendEmptyMessage(H.UPDATE_SESSIONS); } + /** + * Destroy MediaSessions + */ public void destroy() { if (D.BUG) Log.d(TAG, "destroy"); mInit = false; mMgr.removeOnActiveSessionsChangedListener(mSessionsListener); } + /** + * Set volume {@code level} to remote media {@code token} + */ public void setVolume(Token token, int level) { final MediaControllerRecord r = mRecords.get(token); if (r == null) { @@ -113,15 +125,17 @@ public class MediaSessions { r.controller.setVolumeTo(level, 0); } - private void onRemoteVolumeChangedH(MediaSession.Token sessionToken, int flags) { + private void onRemoteVolumeChangedH(Token sessionToken, int flags) { final MediaController controller = new MediaController(mContext, sessionToken); - if (D.BUG) Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " " - + Util.audioManagerFlagsToString(flags)); + if (D.BUG) { + Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " " + + Util.audioManagerFlagsToString(flags)); + } final Token token = controller.getSessionToken(); mCallbacks.onRemoteVolumeChanged(token, flags); } - private void onUpdateRemoteControllerH(MediaSession.Token sessionToken) { + private void onUpdateRemoteControllerH(Token sessionToken) { final MediaController controller = sessionToken != null ? new MediaController(mContext, sessionToken) : null; final String pkg = controller != null ? controller.getPackageName() : null; @@ -191,7 +205,8 @@ public class MediaSessions { if (appLabel.length() > 0) { return appLabel; } - } catch (NameNotFoundException e) { } + } catch (NameNotFoundException e) { + } return pkg; } @@ -240,29 +255,11 @@ public class MediaSessions { } } - public static void dumpMediaSessions(Context context) { - final MediaSessionManager mgr = (MediaSessionManager) context - .getSystemService(Context.MEDIA_SESSION_SERVICE); - try { - final List<MediaController> controllers = mgr.getActiveSessions(null); - final int N = controllers.size(); - if (D.BUG) Log.d(TAG, N + " controllers"); - for (int i = 0; i < N; i++) { - final StringWriter sw = new StringWriter(); - final PrintWriter pw = new PrintWriter(sw, true); - dump(i + 1, pw, controllers.get(i)); - if (D.BUG) Log.d(TAG, sw.toString()); - } - } catch (SecurityException e) { - Log.w(TAG, "Not allowed to get sessions", e); - } - } - private final class MediaControllerRecord extends MediaController.Callback { - private final MediaController controller; + public final MediaController controller; - private boolean sentRemote; - private String name; + public boolean sentRemote; + public String name; private MediaControllerRecord(MediaController controller) { this.controller = controller; @@ -274,8 +271,10 @@ public class MediaSessions { @Override public void onAudioInfoChanged(PlaybackInfo info) { - if (D.BUG) Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info) - + " sentRemote=" + sentRemote); + if (D.BUG) { + Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info) + + " sentRemote=" + sentRemote); + } final boolean remote = isRemote(info); if (!remote && sentRemote) { mCallbacks.onRemoteRemoved(controller.getSessionToken()); @@ -324,22 +323,22 @@ public class MediaSessions { private final OnActiveSessionsChangedListener mSessionsListener = new OnActiveSessionsChangedListener() { - @Override - public void onActiveSessionsChanged(List<MediaController> controllers) { - onActiveSessionsUpdatedH(controllers); - } - }; + @Override + public void onActiveSessionsChanged(List<MediaController> controllers) { + onActiveSessionsUpdatedH(controllers); + } + }; private final IRemoteVolumeController mRvc = new IRemoteVolumeController.Stub() { @Override - public void remoteVolumeChanged(MediaSession.Token sessionToken, int flags) + public void remoteVolumeChanged(Token sessionToken, int flags) throws RemoteException { mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0, sessionToken).sendToTarget(); } @Override - public void updateRemoteController(final MediaSession.Token sessionToken) + public void updateRemoteController(final Token sessionToken) throws RemoteException { mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, sessionToken).sendToTarget(); } @@ -361,18 +360,32 @@ public class MediaSessions { onActiveSessionsUpdatedH(mMgr.getActiveSessions(null)); break; case REMOTE_VOLUME_CHANGED: - onRemoteVolumeChangedH((MediaSession.Token) msg.obj, msg.arg1); + onRemoteVolumeChangedH((Token) msg.obj, msg.arg1); break; case UPDATE_REMOTE_CONTROLLER: - onUpdateRemoteControllerH((MediaSession.Token) msg.obj); + onUpdateRemoteControllerH((Token) msg.obj); break; } } } + /** + * Callback for remote media sessions + */ public interface Callbacks { + /** + * Invoked when remote media session is updated + */ void onRemoteUpdate(Token token, String name, PlaybackInfo pi); + + /** + * Invoked when remote media session is removed + */ void onRemoteRemoved(Token t); + + /** + * Invoked when remote volume is changed + */ void onRemoteVolumeChanged(Token token, int flags); } diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/Util.java b/packages/SettingsLib/src/com/android/settingslib/volume/Util.java new file mode 100644 index 000000000000..4e770aeb861e --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/volume/Util.java @@ -0,0 +1,187 @@ +/* + * 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.settingslib.volume; + +import android.content.Context; +import android.media.AudioManager; +import android.media.MediaMetadata; +import android.media.VolumeProvider; +import android.media.session.MediaController.PlaybackInfo; +import android.media.session.PlaybackState; +import android.telephony.TelephonyManager; +import android.widget.TextView; + +import java.util.Objects; + +/** + * Static helpers for the volume dialog. + */ +public class Util { + + private static final int[] AUDIO_MANAGER_FLAGS = new int[]{ + AudioManager.FLAG_SHOW_UI, + AudioManager.FLAG_VIBRATE, + AudioManager.FLAG_PLAY_SOUND, + AudioManager.FLAG_ALLOW_RINGER_MODES, + AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE, + AudioManager.FLAG_SHOW_VIBRATE_HINT, + AudioManager.FLAG_SHOW_SILENT_HINT, + AudioManager.FLAG_FROM_KEY, + AudioManager.FLAG_SHOW_UI_WARNINGS, + }; + + private static final String[] AUDIO_MANAGER_FLAG_NAMES = new String[]{ + "SHOW_UI", + "VIBRATE", + "PLAY_SOUND", + "ALLOW_RINGER_MODES", + "REMOVE_SOUND_AND_VIBRATE", + "SHOW_VIBRATE_HINT", + "SHOW_SILENT_HINT", + "FROM_KEY", + "SHOW_UI_WARNINGS", + }; + + /** + * Extract log tag from {@code c} + */ + public static String logTag(Class<?> c) { + final String tag = "vol." + c.getSimpleName(); + return tag.length() < 23 ? tag : tag.substring(0, 23); + } + + /** + * Convert media metadata to string + */ + public static String mediaMetadataToString(MediaMetadata metadata) { + if (metadata == null) return null; + return metadata.getDescription().toString(); + } + + /** + * Convert playback info to string + */ + public static String playbackInfoToString(PlaybackInfo info) { + if (info == null) return null; + final String type = playbackInfoTypeToString(info.getPlaybackType()); + final String vc = volumeProviderControlToString(info.getVolumeControl()); + return String.format("PlaybackInfo[vol=%s,max=%s,type=%s,vc=%s],atts=%s", + info.getCurrentVolume(), info.getMaxVolume(), type, vc, info.getAudioAttributes()); + } + + /** + * Convert type of playback info to string + */ + public static String playbackInfoTypeToString(int type) { + switch (type) { + case PlaybackInfo.PLAYBACK_TYPE_LOCAL: + return "LOCAL"; + case PlaybackInfo.PLAYBACK_TYPE_REMOTE: + return "REMOTE"; + default: + return "UNKNOWN_" + type; + } + } + + /** + * Convert state of playback info to string + */ + public static String playbackStateStateToString(int state) { + switch (state) { + case PlaybackState.STATE_NONE: + return "STATE_NONE"; + case PlaybackState.STATE_STOPPED: + return "STATE_STOPPED"; + case PlaybackState.STATE_PAUSED: + return "STATE_PAUSED"; + case PlaybackState.STATE_PLAYING: + return "STATE_PLAYING"; + default: + return "UNKNOWN_" + state; + } + } + + /** + * Convert volume provider control to string + */ + public static String volumeProviderControlToString(int control) { + switch (control) { + case VolumeProvider.VOLUME_CONTROL_ABSOLUTE: + return "VOLUME_CONTROL_ABSOLUTE"; + case VolumeProvider.VOLUME_CONTROL_FIXED: + return "VOLUME_CONTROL_FIXED"; + case VolumeProvider.VOLUME_CONTROL_RELATIVE: + return "VOLUME_CONTROL_RELATIVE"; + default: + return "VOLUME_CONTROL_UNKNOWN_" + control; + } + } + + /** + * Convert {@link PlaybackState} to string + */ + public static String playbackStateToString(PlaybackState playbackState) { + if (playbackState == null) return null; + return playbackStateStateToString(playbackState.getState()) + " " + playbackState; + } + + /** + * Convert audio manager flags to string + */ + public static String audioManagerFlagsToString(int value) { + return bitFieldToString(value, AUDIO_MANAGER_FLAGS, AUDIO_MANAGER_FLAG_NAMES); + } + + protected static String bitFieldToString(int value, int[] values, String[] names) { + if (value == 0) return ""; + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < values.length; i++) { + if ((value & values[i]) != 0) { + if (sb.length() > 0) sb.append(','); + sb.append(names[i]); + } + value &= ~values[i]; + } + if (value != 0) { + if (sb.length() > 0) sb.append(','); + sb.append("UNKNOWN_").append(value); + } + return sb.toString(); + } + + private static CharSequence emptyToNull(CharSequence str) { + return str == null || str.length() == 0 ? null : str; + } + + /** + * Set text for specific {@link TextView} + */ + public static boolean setText(TextView tv, CharSequence text) { + if (Objects.equals(emptyToNull(tv.getText()), emptyToNull(text))) return false; + tv.setText(text); + return true; + } + + /** + * Return {@code true} if it is voice capable + */ + public static boolean isVoiceCapable(Context context) { + final TelephonyManager telephony = + (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + return telephony != null && telephony.isVoiceCapable(); + } +} diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png Binary files differdeleted file mode 100644 index 035a4dffb026..000000000000 --- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/qs_detail_background.xml b/packages/SystemUI/res/drawable/qs_detail_background.xml index 84c793f6abd6..672abf14774e 100644 --- a/packages/SystemUI/res/drawable/qs_detail_background.xml +++ b/packages/SystemUI/res/drawable/qs_detail_background.xml @@ -14,6 +14,20 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <transition xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:drawable="@color/qs_detail_transition" /> - <item android:drawable="?android:attr/colorPrimary" /> + <item> + <inset> + <shape> + <solid android:color="@color/qs_detail_transition"/> + <corners android:radius="?android:attr/dialogCornerRadius" /> + </shape> + </inset> + </item> + <item> + <inset> + <shape> + <solid android:color="?android:attr/colorPrimary"/> + <corners android:radius="?android:attr/dialogCornerRadius" /> + </shape> + </inset> + </item> </transition>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout-land/global_actions_grid.xml b/packages/SystemUI/res/layout-land/global_actions_grid.xml index 480f5235f75a..235d0fc62e2d 100644 --- a/packages/SystemUI/res/layout-land/global_actions_grid.xml +++ b/packages/SystemUI/res/layout-land/global_actions_grid.xml @@ -10,14 +10,12 @@ android:gravity="top|right" android:clipChildren="false" > - <LinearLayout android:layout_height="match_parent" android:layout_width="wrap_content" android:gravity="top|right" android:padding="0dp" android:orientation="vertical" - android:layoutDirection="ltr" android:layout_marginRight="@dimen/global_actions_grid_container_bottom_margin" > <!-- Grid of action items --> @@ -26,7 +24,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - android:layoutDirection="ltr" android:layout_marginTop="@dimen/global_actions_grid_side_margin" android:translationZ="@dimen/global_actions_translate" android:paddingLeft="@dimen/global_actions_grid_horizontal_padding" @@ -39,25 +36,21 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:layoutDirection="ltr" - android:orientation="horizontal" + android:layoutDirection="locale" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:layoutDirection="ltr" - android:orientation="horizontal" + android:layoutDirection="locale" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:layoutDirection="ltr" - android:orientation="horizontal" + android:layoutDirection="locale" /> </com.android.systemui.globalactions.ListGridLayout> - <!-- For separated items--> <LinearLayout android:id="@+id/separated_button" diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml index 4f868263226d..e028214532f0 100644 --- a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml +++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml @@ -10,7 +10,6 @@ android:gravity="top|left" android:clipChildren="false" > - <LinearLayout android:layout_height="match_parent" android:layout_width="wrap_content" @@ -37,11 +36,11 @@ android:gravity="center" android:translationZ="@dimen/global_actions_translate" /> - <!-- Grid of action items --> <com.android.systemui.globalactions.ListGridLayout android:id="@android:id/list" android:layout_gravity="bottom|left" + android:gravity="right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" @@ -54,28 +53,22 @@ android:background="?android:attr/colorBackgroundFloating" > <LinearLayout - android:layout_gravity="bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:layoutDirection="rtl" - android:orientation="horizontal" + android:layoutDirection="locale" /> <LinearLayout - android:layout_gravity="bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:layoutDirection="rtl" - android:orientation="horizontal" + android:layoutDirection="locale" /> <LinearLayout - android:layout_gravity="bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:layoutDirection="rtl" - android:orientation="horizontal" + android:layoutDirection="locale" /> </com.android.systemui.globalactions.ListGridLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml index 729e96ebc22e..a620a8eb144b 100644 --- a/packages/SystemUI/res/layout/global_actions_grid.xml +++ b/packages/SystemUI/res/layout/global_actions_grid.xml @@ -10,7 +10,6 @@ android:gravity="bottom|center" android:clipChildren="false" > - <LinearLayout android:layout_height="wrap_content" android:layout_width="match_parent" @@ -35,14 +34,13 @@ android:gravity="center" android:translationZ="@dimen/global_actions_translate" /> - <!-- Grid of action items --> <com.android.systemui.globalactions.ListGridLayout android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="horizontal" - android:layoutDirection="rtl" + android:orientation="vertical" + android:gravity="right" android:layout_marginRight="@dimen/global_actions_grid_side_margin" android:translationZ="@dimen/global_actions_translate" android:paddingLeft="@dimen/global_actions_grid_horizontal_padding" @@ -55,19 +53,19 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:orientation="vertical" + android:layoutDirection="locale" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:orientation="vertical" + android:layoutDirection="locale" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" - android:orientation="vertical" + android:layoutDirection="locale" /> </com.android.systemui.globalactions.ListGridLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 863c1ccd7eaf..bd9d3fb43528 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -44,7 +44,7 @@ android:id="@+id/pkgname" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info" android:layout_marginStart="3dp" android:layout_marginEnd="2dp" android:singleLine="true" @@ -54,7 +54,7 @@ android:id="@+id/pkg_divider" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info" android:layout_marginStart="2dp" android:layout_marginEnd="2dp" android:text="@*android:string/notification_header_divider_symbol" @@ -64,7 +64,7 @@ android:id="@+id/delegate_name" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info" android:layout_marginStart="2dp" android:layout_marginEnd="2dp" android:ellipsize="end" @@ -129,7 +129,7 @@ asked for it --> android:id="@+id/group_name" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" android:layout_marginStart="2dp" android:layout_marginEnd="2dp" android:ellipsize="end" @@ -139,7 +139,7 @@ asked for it --> android:id="@+id/pkg_group_divider" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" android:layout_marginStart="2dp" android:layout_marginEnd="2dp" android:text="@*android:string/notification_header_divider_symbol" @@ -151,7 +151,7 @@ asked for it --> android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" - style="@android:style/TextAppearance.Material.Notification.Title" + style="@*android:style/TextAppearance.DeviceDefault.Notification.Title" android:layout_toEndOf="@id/pkg_group_divider"/> </RelativeLayout> <!-- Question prompt --> @@ -159,7 +159,7 @@ asked for it --> android:id="@+id/block_prompt" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@android:style/TextAppearance.Material.Notification" /> + style="@*android:style/TextAppearance.DeviceDefault.Notification" /> </LinearLayout> <!-- Settings and Done buttons --> diff --git a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl index 586cdf3fbaae..716e1272f871 100644 --- a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl +++ b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl @@ -1,27 +1,76 @@ precision mediump float; +// The actual wallpaper texture. uniform sampler2D uTexture; -uniform float uCenterReveal; + +// The 85th percenile for the luminance histogram of the image (a value between 0 and 1). +// This value represents the point in histogram that includes 85% of the pixels of the image. +uniform float uPer85; + +// Reveal is the animation value that goes from 1 (the image is hidden) to 0 (the image is visible). uniform float uReveal; + +// The opacity of locked screen (constant value). uniform float uAod2Opacity; varying vec2 vTextureCoordinates; +/* + * Calculates the relative luminance of the pixel. + */ vec3 luminosity(vec3 color) { float lum = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; return vec3(lum); } vec4 transform(vec3 diffuse) { - // TODO: Add well comments here, tracking on b/123615467. + // Getting the luminance for this pixel vec3 lum = luminosity(diffuse); - diffuse = mix(diffuse, lum, smoothstep(0., uCenterReveal, uReveal)); - float val = mix(uReveal, uCenterReveal, step(uCenterReveal, uReveal)); - diffuse = smoothstep(val, 1.0, diffuse); - diffuse *= uAod2Opacity * (1. - smoothstep(uCenterReveal, 1., uReveal)); + + /* + * while the reveal > per85, it shows the luminance image (B&W image) + * then when moving passed that value, the image gets colored. + */ + float trans = smoothstep(0., uPer85, uReveal); + diffuse = mix(diffuse, lum, trans); + + // 'lower' value represents the capped 'reveal' value to the range [0, per85] + float selector = step(uPer85, uReveal); + float lower = mix(uReveal, uPer85, selector); + + /* + * Remaps image: + * - from reveal=1 to reveal=per85 => lower=per85, diffuse=luminance + * That means that remaps black and white image pixel + * from a possible values of [0,1] to [per85, 1] (if the pixel is darker than per85, + * it's gonna be black, if it's between per85 and 1, it's gonna be gray + * and if it's 1 it's gonna be white). + * - from reveal=per85 to reveal=0 => lower=reveal, 'diffuse' changes from luminance to color + * That means that remaps each image pixel color (rgb) + * from a possible values of [0,1] to [lower, 1] (if the pixel color is darker than 'lower', + * it's gonna be 0, if it's between 'lower' and 1, it's gonna be remap to a value + * between 0 and 1 and if it's 1 it's gonna be 1). + * - if reveal=0 => lower=0, diffuse=color image + * The image is shown as it is, colored. + */ + vec3 remaps = smoothstep(lower, 1., diffuse); + + // Interpolate between diffuse and remaps using reveal to avoid over saturation. + diffuse = mix(diffuse, remaps, uReveal); + + /* + * Fades in the pixel value: + * - if reveal=1 => fadeInOpacity=0 + * - from reveal=1 to reveal=per85 => 0<=fadeInOpacity<=1 + * - if reveal>per85 => fadeInOpacity=1 + */ + float fadeInOpacity = 1. - smoothstep(uPer85, 1., uReveal); + diffuse *= uAod2Opacity * fadeInOpacity; + return vec4(diffuse.r, diffuse.g, diffuse.b, 1.); } void main() { + // gets the pixel value of the wallpaper for this uv coordinates on screen. vec4 fragColor = texture2D(uTexture, vTextureCoordinates); gl_FragColor = transform(fragColor.rgb); }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 563b0077c7f4..d40fa661192c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -1,6 +1,7 @@ package com.android.keyguard; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.app.WallpaperManager; @@ -31,6 +32,9 @@ import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Arrays; import java.util.TimeZone; /** @@ -148,6 +152,7 @@ public class KeyguardClockSwitch extends RelativeLayout { Dependency.get(StatusBarStateController.class).removeCallback(mStateListener); Dependency.get(SysuiColorExtractor.class) .removeOnColorsChangedListener(mColorsListener); + setClockPlugin(null); } private void setClockPlugin(ClockPlugin plugin) { @@ -332,6 +337,19 @@ public class KeyguardClockSwitch extends RelativeLayout { return mStateListener; } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("KeyguardClockSwitch:"); + pw.println(" mClockPlugin: " + mClockPlugin); + pw.println(" mClockView: " + mClockView); + pw.println(" mSmallClockFrame: " + mSmallClockFrame); + pw.println(" mBigClockContainer: " + mBigClockContainer); + pw.println(" mKeyguardStatusArea: " + mKeyguardStatusArea); + pw.println(" mDarkAmount: " + mDarkAmount); + pw.println(" mShowingHeader: " + mShowingHeader); + pw.println(" mSupportsDarkText: " + mSupportsDarkText); + pw.println(" mColorPalette: " + Arrays.toString(mColorPalette)); + } + /** * Special layout transition that scales the clock view as its bounds change, to make it look * like the text is shrinking. @@ -371,11 +389,23 @@ public class KeyguardClockSwitch extends RelativeLayout { boundsAnimator.addUpdateListener(animation -> { float scale = MathUtils.lerp(startScale, 1f /* stop */, animation.getAnimatedFraction()); - mClockView.setPivotX(mClockView.getWidth() / 2); + mClockView.setPivotX(mClockView.getWidth() / 2f); mClockView.setPivotY(0); mClockView.setScaleX(scale); mClockView.setScaleY(scale); }); + boundsAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + mClockView.setScaleX(1f); + mClockView.setScaleY(1f); + } + + @Override + public void onAnimationCancel(Animator animator) { + onAnimationEnd(animator); + } + }); } return animator; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 2040a76b61d3..8ebe1ae80d26 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -64,6 +64,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.tuner.TunerService; import com.android.systemui.util.wakelock.KeepAwakeAnimationListener; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -174,6 +176,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe if (mContentChangeListener != null) { mContentChangeListener.run(); } + Trace.endSection(); return; } @@ -375,6 +378,17 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe Trace.endSection(); } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("KeyguardSliceView:"); + pw.println(" mClickActions: " + mClickActions); + pw.println(" mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE)); + pw.println(" mRow: " + (mRow == null ? "null" : mRow.getVisibility() == VISIBLE)); + pw.println(" mTextColor: " + Integer.toHexString(mTextColor)); + pw.println(" mDarkAmount: " + mDarkAmount); + pw.println(" mSlice: " + mSlice); + pw.println(" mHasHeader: " + mHasHeader); + } + public static class Row extends LinearLayout { /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 17546c512778..808e264258da 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -41,6 +41,8 @@ import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.statusbar.policy.ConfigurationController; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Locale; import java.util.TimeZone; @@ -289,6 +291,24 @@ public class KeyguardStatusView extends GridLayout implements return false; } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("KeyguardStatusView:"); + pw.println(" mOwnerInfo: " + (mOwnerInfo == null + ? "null" : mOwnerInfo.getVisibility() == VISIBLE)); + pw.println(" mPulsing: " + mPulsing); + pw.println(" mDarkAmount: " + mDarkAmount); + pw.println(" mTextColor: " + Integer.toHexString(mTextColor)); + if (mLogoutView != null) { + pw.println(" logout visible: " + (mLogoutView.getVisibility() == VISIBLE)); + } + if (mClockView != null) { + mClockView.dump(fd, pw, args); + } + if (mKeyguardSlice != null) { + mKeyguardSlice.dump(fd, pw, args); + } + } + // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. // This is an optimization to ensure we only recompute the patterns when the inputs change. private static final class Patterns { diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java index f5451e952dd9..26c5ef95981f 100644 --- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -90,7 +90,7 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable { } @Override - public ViewGroup getParentView(boolean separated, int index, boolean reverse) { + public ViewGroup getParentView(boolean separated, int index, int rotation) { if (separated) { return getSeparatedView(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java index 8c49d56ae348..8259da6efe2d 100644 --- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java +++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java @@ -57,12 +57,12 @@ public abstract class MultiListLayout extends LinearLayout { * @param separated Whether or not this index refers to a position in the separated or list * container. * @param index The index of the item within the container. - * @param reverse If the MultiListLayout contains sub-lists within the list container, reverse - * the order that they are filled. + * @param rotation Specifies the rotation of the device, which is used in some cases to + * determine child ordering. * @return The parent ViewGroup which will be used to contain the specified item * after it has been added to the layout. */ - public abstract ViewGroup getParentView(boolean separated, int index, boolean reverse); + public abstract ViewGroup getParentView(boolean separated, int index, int rotation); /** * Sets the divided view, which may have a differently-colored background. diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 3fa6035387c7..c16c91bd4625 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -96,6 +96,7 @@ import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolat import java.util.ArrayList; import java.util.List; +import java.util.Locale; /** * Helper to show the global actions dialog. Each item is an {@link Action} that @@ -1546,33 +1547,40 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton); mGlobalActionsLayout.setExpectedListItemCount(listActions.size()); mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size()); + int rotation = RotationUtils.getRotation(mContext); + + boolean reverse = false; // should we add items to parents in the reverse order? + if (isGridEnabled(mContext)) { + if (rotation == RotationUtils.ROTATION_NONE + || rotation == RotationUtils.ROTATION_SEASCAPE) { + reverse = !reverse; // if we're in portrait or seascape, reverse items + } + if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) + == View.LAYOUT_DIRECTION_RTL) { + reverse = !reverse; // if we're in an RTL language, reverse items (again) + } + } for (int i = 0; i < mAdapter.getCount(); i++) { Action action = mAdapter.getItem(i); int separatedIndex = separatedActions.indexOf(action); ViewGroup parent; if (separatedIndex != -1) { - parent = mGlobalActionsLayout.getParentView(true, separatedIndex, false); + parent = mGlobalActionsLayout.getParentView(true, separatedIndex, rotation); } else { - boolean reverse = false; - - // If we're using the grid layout and we're in seascape, reverse the order - // of sublists to make sure they render in the correct positions, - // since we can't reverse vertical LinearLayouts through the layout xml. - - if (isGridEnabled(mContext) && RotationUtils.getRotation(mContext) - == RotationUtils.ROTATION_SEASCAPE) { - reverse = true; - } int listIndex = listActions.indexOf(action); - parent = mGlobalActionsLayout.getParentView(false, listIndex, reverse); + parent = mGlobalActionsLayout.getParentView(false, listIndex, rotation); } View v = mAdapter.getView(i, null, parent); final int pos = i; v.setOnClickListener(view -> mClickListener.onClick(this, pos)); v.setOnLongClickListener(view -> mLongClickListener.onItemLongClick(null, v, pos, 0)); - parent.addView(v); + if (reverse) { + parent.addView(v, 0); // reverse order of items + } else { + parent.addView(v); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java index 1d042776efc9..036d8ca3afb6 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java @@ -23,6 +23,7 @@ import android.view.ViewGroup; import com.android.systemui.HardwareBgDrawable; import com.android.systemui.MultiListLayout; +import com.android.systemui.util.leak.RotationUtils; /** * Grid-based implementation of the button layout created by the global actions dialog. @@ -83,11 +84,18 @@ public class GlobalActionsGridLayout extends MultiListLayout { } @Override - public ViewGroup getParentView(boolean separated, int index, boolean reverseOrder) { + public ViewGroup getParentView(boolean separated, int index, int rotation) { if (separated) { return getSeparatedView(); } else { - return getListView().getParentView(index, reverseOrder); + switch (rotation) { + case RotationUtils.ROTATION_LANDSCAPE: + return getListView().getParentView(index, false, true); + case RotationUtils.ROTATION_SEASCAPE: + return getListView().getParentView(index, true, true); + default: + return getListView().getParentView(index, false, false); + } } } @@ -96,6 +104,6 @@ public class GlobalActionsGridLayout extends MultiListLayout { */ @Override public void setDivisionView(View v) { - + // do nothing } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java index d5dcd74c7ea8..4df1c5a43a1b 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java @@ -62,11 +62,11 @@ public class ListGridLayout extends LinearLayout { /** * Get the parent view associated with the item which should be placed at the given position. */ - public ViewGroup getParentView(int index, boolean reverseSublists) { + public ViewGroup getParentView(int index, boolean reverseSublists, boolean swapRowsAndColumns) { if (mRows == 0) { return null; } - int column = getParentViewIndex(index, reverseSublists); + int column = getParentViewIndex(index, reverseSublists, swapRowsAndColumns); return (ViewGroup) getChildAt(column); } @@ -74,13 +74,18 @@ public class ListGridLayout extends LinearLayout { return getChildCount() - (index + 1); } - private int getParentViewIndex(int index, boolean reverseSublists) { - int column = (int) Math.floor(index / mRows); - int columnCount = getChildCount(); + private int getParentViewIndex(int index, boolean reverseSublists, boolean swapRowsAndColumns) { + int sublistIndex; + ViewGroup row; + if (swapRowsAndColumns) { + sublistIndex = (int) Math.floor(index / mRows); + } else { + sublistIndex = index % mRows; + } if (reverseSublists) { - column = reverseSublistIndex(column); + sublistIndex = reverseSublistIndex(sublistIndex); } - return column; + return sublistIndex; } /** diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java index 19d85b155cba..a313336e3d71 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java @@ -50,7 +50,7 @@ class ImageGLWallpaper { static final String A_POSITION = "aPosition"; static final String A_TEXTURE_COORDINATES = "aTextureCoordinates"; - static final String U_CENTER_REVEAL = "uCenterReveal"; + static final String U_PER85 = "uPer85"; static final String U_REVEAL = "uReveal"; static final String U_AOD2OPACITY = "uAod2Opacity"; static final String U_TEXTURE = "uTexture"; @@ -87,7 +87,7 @@ class ImageGLWallpaper { private int mAttrPosition; private int mAttrTextureCoordinates; private int mUniAod2Opacity; - private int mUniCenterReveal; + private int mUniPer85; private int mUniReveal; private int mUniTexture; private int mTextureId; @@ -131,7 +131,7 @@ class ImageGLWallpaper { private void setupUniforms() { mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY); - mUniCenterReveal = mProgram.getUniformHandle(U_CENTER_REVEAL); + mUniPer85 = mProgram.getUniformHandle(U_PER85); mUniReveal = mProgram.getUniformHandle(U_REVEAL); mUniTexture = mProgram.getUniformHandle(U_TEXTURE); } @@ -144,8 +144,8 @@ class ImageGLWallpaper { return mAttrTextureCoordinates; case U_AOD2OPACITY: return mUniAod2Opacity; - case U_CENTER_REVEAL: - return mUniCenterReveal; + case U_PER85: + return mUniPer85; case U_REVEAL: return mUniReveal; case U_TEXTURE: diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java index 991b1161dde2..72950088eb39 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -93,13 +93,13 @@ public class ImageWallpaperRenderer implements GLSurfaceView.Renderer, @Override public void onDrawFrame(GL10 gl) { - float threshold = mImageProcessHelper.getPercentile85(); + float per85 = mImageProcessHelper.getPercentile85(); float reveal = mImageRevealHelper.getReveal(); glClear(GL_COLOR_BUFFER_BIT); glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), 1); - glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_CENTER_REVEAL), threshold); + glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_PER85), per85); glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal); mWallpaper.useTexture(); diff --git a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt new file mode 100644 index 000000000000..d7a2d9acf3b5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt @@ -0,0 +1,55 @@ +package com.android.systemui.power + +import com.android.systemui.power.PowerUI.NO_ESTIMATE_AVAILABLE + +/** + * A simple data class to snapshot battery state when a particular check for the + * low battery warning is running in the background. + */ +data class BatteryStateSnapshot( + val batteryLevel: Int, + val isPowerSaver: Boolean, + val plugged: Boolean, + val bucket: Int, + val batteryStatus: Int, + val severeLevelThreshold: Int, + val lowLevelThreshold: Int, + val timeRemainingMillis: Long, + val severeThresholdMillis: Long, + val lowThresholdMillis: Long, + val isBasedOnUsage: Boolean +) { + /** + * Returns whether hybrid warning logic/copy should be used for this snapshot + */ + var isHybrid: Boolean = false + private set + + init { + this.isHybrid = true + } + + constructor( + batteryLevel: Int, + isPowerSaver: Boolean, + plugged: Boolean, + bucket: Int, + batteryStatus: Int, + severeLevelThreshold: Int, + lowLevelThreshold: Int + ) : this( + batteryLevel, + isPowerSaver, + plugged, + bucket, + batteryStatus, + severeLevelThreshold, + lowLevelThreshold, + NO_ESTIMATE_AVAILABLE.toLong(), + NO_ESTIMATE_AVAILABLE.toLong(), + NO_ESTIMATE_AVAILABLE.toLong(), + false + ) { + this.isHybrid = false + } +} diff --git a/packages/SystemUI/src/com/android/systemui/power/Estimate.java b/packages/SystemUI/src/com/android/systemui/power/Estimate.java deleted file mode 100644 index 12a8f0a435b4..000000000000 --- a/packages/SystemUI/src/com/android/systemui/power/Estimate.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.android.systemui.power; - -public class Estimate { - public final long estimateMillis; - public final boolean isBasedOnUsage; - - public Estimate(long estimateMillis, boolean isBasedOnUsage) { - this.estimateMillis = estimateMillis; - this.isBasedOnUsage = isBasedOnUsage; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/power/Estimate.kt b/packages/SystemUI/src/com/android/systemui/power/Estimate.kt new file mode 100644 index 000000000000..dca0d45c1c9f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/power/Estimate.kt @@ -0,0 +1,3 @@ +package com.android.systemui.power + +data class Estimate(val estimateMillis: Long, val isBasedOnUsage: Boolean)
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index fdb0b36ee51e..41bcab53f8e9 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -134,10 +134,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private int mShowing; private long mWarningTriggerTimeMs; - - private Estimate mEstimate; - private long mLowWarningThreshold; - private long mSevereWarningThreshold; private boolean mWarning; private boolean mShowAutoSaverSuggestion; private boolean mPlaySound; @@ -148,6 +144,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private SystemUIDialog mHighTempDialog; private SystemUIDialog mThermalShutdownDialog; @VisibleForTesting SystemUIDialog mUsbHighTempDialog; + private BatteryStateSnapshot mCurrentBatterySnapshot; /** */ @@ -195,17 +192,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } @Override - public void updateEstimate(Estimate estimate) { - mEstimate = estimate; - if (estimate.estimateMillis <= mLowWarningThreshold) { - mWarningTriggerTimeMs = System.currentTimeMillis(); - } - } - - @Override - public void updateThresholds(long lowThreshold, long severeThreshold) { - mLowWarningThreshold = lowThreshold; - mSevereWarningThreshold = severeThreshold; + public void updateSnapshot(BatteryStateSnapshot snapshot) { + mCurrentBatterySnapshot = snapshot; } private void updateNotification() { @@ -254,15 +242,17 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { protected void showWarningNotification() { final String percentage = NumberFormat.getPercentInstance() - .format((double) mBatteryLevel / 100.0); + .format((double) mCurrentBatterySnapshot.getBatteryLevel() / 100.0); - // get standard notification copy + // get shared standard notification copy String title = mContext.getString(R.string.battery_low_title); - String contentText = mContext.getString(R.string.battery_low_percent_format, percentage); + String contentText; - // override notification copy if hybrid notification enabled - if (mEstimate != null) { + // get correct content text if notification is hybrid or not + if (mCurrentBatterySnapshot.isHybrid()) { contentText = getHybridContentString(percentage); + } else { + contentText = mContext.getString(R.string.battery_low_percent_format, percentage); } final Notification.Builder nb = @@ -282,8 +272,9 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } // Make the notification red if the percentage goes below a certain amount or the time // remaining estimate is disabled - if (mEstimate == null || mBucket < 0 - || mEstimate.estimateMillis < mSevereWarningThreshold) { + if (!mCurrentBatterySnapshot.isHybrid() || mBucket < 0 + || mCurrentBatterySnapshot.getTimeRemainingMillis() + < mCurrentBatterySnapshot.getSevereThresholdMillis()) { nb.setColor(Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorError)); } @@ -324,10 +315,10 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private String getHybridContentString(String percentage) { return PowerUtil.getBatteryRemainingStringFormatted( - mContext, - mEstimate.estimateMillis, - percentage, - mEstimate.isBasedOnUsage); + mContext, + mCurrentBatterySnapshot.getTimeRemainingMillis(), + percentage, + mCurrentBatterySnapshot.isBasedOnUsage()); } private PendingIntent pendingBroadcast(String action) { diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index e27c25efd88f..18638606a251 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -55,6 +55,7 @@ import java.util.Arrays; import java.util.concurrent.Future; public class PowerUI extends SystemUI { + static final String TAG = "PowerUI"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS; @@ -63,6 +64,7 @@ public class PowerUI extends SystemUI { static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3; private static final int CHARGE_CYCLE_PERCENT_RESET = 45; private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis(); + public static final int NO_ESTIMATE_AVAILABLE = -1; private final Handler mHandler = new Handler(); @VisibleForTesting @@ -71,13 +73,9 @@ public class PowerUI extends SystemUI { private PowerManager mPowerManager; private WarningsUI mWarnings; private final Configuration mLastConfiguration = new Configuration(); - private long mTimeRemaining = Long.MAX_VALUE; private int mPlugType = 0; private int mInvalidCharger = 0; private EnhancedEstimates mEnhancedEstimates; - private Estimate mLastEstimate; - private boolean mLowWarningShownThisChargeCycle; - private boolean mSevereWarningShownThisChargeCycle; private Future mLastShowWarningTask; private boolean mEnableSkinTemperatureWarning; private boolean mEnableUsbTemperatureAlarm; @@ -87,6 +85,10 @@ public class PowerUI extends SystemUI { private long mScreenOffTime = -1; + @VisibleForTesting boolean mLowWarningShownThisChargeCycle; + @VisibleForTesting boolean mSevereWarningShownThisChargeCycle; + @VisibleForTesting BatteryStateSnapshot mCurrentBatteryStateSnapshot; + @VisibleForTesting BatteryStateSnapshot mLastBatteryStateSnapshot; @VisibleForTesting IThermalService mThermalService; @VisibleForTesting int mBatteryLevel = 100; @@ -205,6 +207,7 @@ public class PowerUI extends SystemUI { mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1); final int oldInvalidCharger = mInvalidCharger; mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0); + mLastBatteryStateSnapshot = mCurrentBatteryStateSnapshot; final boolean plugged = mPlugType != 0; final boolean oldPlugged = oldPlugType != 0; @@ -233,16 +236,22 @@ public class PowerUI extends SystemUI { mWarnings.dismissInvalidChargerWarning(); } else if (mWarnings.isInvalidChargerWarningShowing()) { // if invalid charger is showing, don't show low battery + if (DEBUG) { + Slog.d(TAG, "Bad Charger"); + } return; } // Show the correct version of low battery warning if needed if (mLastShowWarningTask != null) { mLastShowWarningTask.cancel(true); + if (DEBUG) { + Slog.d(TAG, "cancelled task"); + } } mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> { - maybeShowBatteryWarning( - oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket); + maybeShowBatteryWarningV2( + plugged, bucket); }); } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { @@ -257,118 +266,176 @@ public class PowerUI extends SystemUI { } } - protected void maybeShowBatteryWarning(int oldBatteryLevel, boolean plugged, boolean oldPlugged, - int oldBucket, int bucket) { - boolean isPowerSaver = mPowerManager.isPowerSaveMode(); - // only play SFX when the dialog comes up or the bucket changes - final boolean playSound = bucket != oldBucket || oldPlugged; + protected void maybeShowBatteryWarningV2(boolean plugged, int bucket) { final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled(); + final boolean isPowerSaverMode = mPowerManager.isPowerSaveMode(); + + // Stick current battery state into an immutable container to determine if we should show + // a warning. + if (DEBUG) { + Slog.d(TAG, "evaluating which notification to show"); + } if (hybridEnabled) { - Estimate estimate = mLastEstimate; - if (estimate == null || mBatteryLevel != oldBatteryLevel) { - estimate = mEnhancedEstimates.getEstimate(); - mLastEstimate = estimate; + if (DEBUG) { + Slog.d(TAG, "using hybrid"); } - // Turbo is not always booted once SysUI is running so we have to make sure we actually - // get data back - if (estimate != null) { - mTimeRemaining = estimate.estimateMillis; - mWarnings.updateEstimate(estimate); - mWarnings.updateThresholds(mEnhancedEstimates.getLowWarningThreshold(), - mEnhancedEstimates.getSevereWarningThreshold()); - - // if we are now over 45% battery & 6 hours remaining we can trigger hybrid - // notification again - if (mBatteryLevel >= CHARGE_CYCLE_PERCENT_RESET - && mTimeRemaining > SIX_HOURS_MILLIS) { - mLowWarningShownThisChargeCycle = false; - mSevereWarningShownThisChargeCycle = false; - } + Estimate estimate = refreshEstimateIfNeeded(); + mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode, + plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1], + mLowBatteryReminderLevels[0], estimate.getEstimateMillis(), + mEnhancedEstimates.getSevereWarningThreshold(), + mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage()); + } else { + if (DEBUG) { + Slog.d(TAG, "using standard"); } + mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode, + plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1], + mLowBatteryReminderLevels[0]); } - if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket, - mTimeRemaining, isPowerSaver, mBatteryStatus)) { - mWarnings.showLowBatteryWarning(playSound); + mWarnings.updateSnapshot(mCurrentBatteryStateSnapshot); + if (mCurrentBatteryStateSnapshot.isHybrid()) { + maybeShowHybridWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot); + } else { + maybeShowBatteryWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot); + } + } + // updates the time estimate if we don't have one or battery level has changed. + @VisibleForTesting + Estimate refreshEstimateIfNeeded() { + if (mLastBatteryStateSnapshot == null + || mLastBatteryStateSnapshot.getTimeRemainingMillis() == NO_ESTIMATE_AVAILABLE + || mBatteryLevel != mLastBatteryStateSnapshot.getBatteryLevel()) { + final Estimate estimate = mEnhancedEstimates.getEstimate(); + if (DEBUG) { + Slog.d(TAG, "updated estimate: " + estimate.getEstimateMillis()); + } + return estimate; + } + return new Estimate(mLastBatteryStateSnapshot.getTimeRemainingMillis(), + mLastBatteryStateSnapshot.isBasedOnUsage()); + } + + @VisibleForTesting + void maybeShowHybridWarning(BatteryStateSnapshot currentSnapshot, + BatteryStateSnapshot lastSnapshot) { + // if we are now over 45% battery & 6 hours remaining so we can trigger hybrid + // notification again + if (currentSnapshot.getBatteryLevel() >= CHARGE_CYCLE_PERCENT_RESET + && currentSnapshot.getTimeRemainingMillis() > SIX_HOURS_MILLIS) { + mLowWarningShownThisChargeCycle = false; + mSevereWarningShownThisChargeCycle = false; + if (DEBUG) { + Slog.d(TAG, "Charge cycle reset! Can show warnings again"); + } + } + + final boolean playSound = currentSnapshot.getBucket() != lastSnapshot.getBucket() + || lastSnapshot.getPlugged(); + + if (shouldShowHybridWarning(currentSnapshot)) { + mWarnings.showLowBatteryWarning(playSound); // mark if we've already shown a warning this cycle. This will prevent the notification // trigger from spamming users by only showing low/critical warnings once per cycle - if (hybridEnabled) { - if (mTimeRemaining <= mEnhancedEstimates.getSevereWarningThreshold() - || mBatteryLevel <= mLowBatteryReminderLevels[1]) { - mSevereWarningShownThisChargeCycle = true; - mLowWarningShownThisChargeCycle = true; - } else { - mLowWarningShownThisChargeCycle = true; + if (currentSnapshot.getTimeRemainingMillis() + <= currentSnapshot.getSevereLevelThreshold() + || currentSnapshot.getBatteryLevel() <= mLowBatteryReminderLevels[1]) { + mSevereWarningShownThisChargeCycle = true; + mLowWarningShownThisChargeCycle = true; + if (DEBUG) { + Slog.d(TAG, "Severe warning marked as shown this cycle"); } + } else { + Slog.d(TAG, "Low warning marked as shown this cycle"); + mLowWarningShownThisChargeCycle = true; + } + + } else if (shouldDismissHybridWarning(currentSnapshot)) { + if (DEBUG) { + Slog.d(TAG, "Dismissing warning"); } - } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining, - isPowerSaver)) { mWarnings.dismissLowBatteryWarning(); } else { + if (DEBUG) { + Slog.d(TAG, "Updating warning"); + } mWarnings.updateLowBatteryWarning(); } } @VisibleForTesting - boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket, - int bucket, long timeRemaining, boolean isPowerSaver, int batteryStatus) { - if (mEnhancedEstimates.isHybridNotificationEnabled()) { - // triggering logic when enhanced estimate is available - return isEnhancedTrigger(plugged, timeRemaining, isPowerSaver, batteryStatus); - } - // legacy triggering logic - return !plugged - && !isPowerSaver - && (((bucket < oldBucket || oldPlugged) && bucket < 0)) - && batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN; - } - - @VisibleForTesting - boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket, - long timeRemaining, boolean isPowerSaver) { - final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled(); - final boolean hybridWouldDismiss = hybridEnabled - && timeRemaining > mEnhancedEstimates.getLowWarningThreshold(); - final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0); - return (isPowerSaver && !hybridEnabled) - || plugged - || (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled() - || hybridWouldDismiss)); - } - - private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver, - int batteryStatus) { - if (plugged || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { + boolean shouldShowHybridWarning(BatteryStateSnapshot snapshot) { + if (snapshot.getPlugged() + || snapshot.getBatteryStatus() == BatteryManager.BATTERY_STATUS_UNKNOWN) { + Slog.d(TAG, "can't show warning due to - plugged: " + snapshot.getPlugged() + + " status unknown: " + + (snapshot.getBatteryStatus() == BatteryManager.BATTERY_STATUS_UNKNOWN)); return false; } - int warnLevel = mLowBatteryReminderLevels[0]; - int critLevel = mLowBatteryReminderLevels[1]; // Only show the low warning once per charge cycle & no battery saver - final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver - && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold() - || mBatteryLevel <= warnLevel); + final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver() + && (snapshot.getTimeRemainingMillis() < snapshot.getLowThresholdMillis() + || snapshot.getBatteryLevel() <= snapshot.getLowLevelThreshold()); // Only show the severe warning once per charge cycle final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle - && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold() - || mBatteryLevel <= critLevel); + && (snapshot.getTimeRemainingMillis() < snapshot.getSevereThresholdMillis() + || snapshot.getBatteryLevel() <= snapshot.getSevereLevelThreshold()); final boolean canShow = canShowWarning || canShowSevereWarning; if (DEBUG) { - Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: " + Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith battery snapshot:" + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle - + " mEnhancedEstimates.timeremaining: " + timeRemaining - + " mBatteryLevel: " + mBatteryLevel - + " canShowWarning: " + canShowWarning - + " canShowSevereWarning: " + canShowSevereWarning - + " plugged: " + plugged - + " batteryStatus: " + batteryStatus - + " isPowerSaver: " + isPowerSaver); + + "\n" + snapshot.toString()); + } + return canShow; + } + + @VisibleForTesting + boolean shouldDismissHybridWarning(BatteryStateSnapshot snapshot) { + return snapshot.getPlugged() + || snapshot.getTimeRemainingMillis() > snapshot.getLowThresholdMillis(); + } + + protected void maybeShowBatteryWarning( + BatteryStateSnapshot currentSnapshot, + BatteryStateSnapshot lastSnapshot) { + final boolean playSound = currentSnapshot.getBucket() != lastSnapshot.getBucket() + || lastSnapshot.getPlugged(); + + if (shouldShowLowBatteryWarning(currentSnapshot, lastSnapshot)) { + mWarnings.showLowBatteryWarning(playSound); + } else if (shouldDismissLowBatteryWarning(currentSnapshot, lastSnapshot)) { + mWarnings.dismissLowBatteryWarning(); + } else { + mWarnings.updateLowBatteryWarning(); } - return canShowWarning || canShowSevereWarning; + } + + @VisibleForTesting + boolean shouldShowLowBatteryWarning( + BatteryStateSnapshot currentSnapshot, + BatteryStateSnapshot lastSnapshot) { + return !currentSnapshot.getPlugged() + && !currentSnapshot.isPowerSaver() + && (((currentSnapshot.getBucket() < lastSnapshot.getBucket() + || lastSnapshot.getPlugged()) + && currentSnapshot.getBucket() < 0)) + && currentSnapshot.getBatteryStatus() != BatteryManager.BATTERY_STATUS_UNKNOWN; + } + + @VisibleForTesting + boolean shouldDismissLowBatteryWarning( + BatteryStateSnapshot currentSnapshot, + BatteryStateSnapshot lastSnapshot) { + return currentSnapshot.isPowerSaver() + || currentSnapshot.getPlugged() + || (currentSnapshot.getBucket() > lastSnapshot.getBucket() + && currentSnapshot.getBucket() > 0); } private void initTemperature() { @@ -453,12 +520,20 @@ public class PowerUI extends SystemUI { mWarnings.dump(pw); } + /** + * The interface to allow PowerUI to communicate with whatever implementation of WarningsUI + * is being used by the system. + */ public interface WarningsUI { - void update(int batteryLevel, int bucket, long screenOffTime); - void updateEstimate(Estimate estimate); - - void updateThresholds(long lowThreshold, long severeThreshold); + /** + * Updates battery and screen info for determining whether to trigger battery warnings or + * not. + * @param batteryLevel The current battery level + * @param bucket The current battery bucket + * @param screenOffTime How long the screen has been off in millis + */ + void update(int batteryLevel, int bucket, long screenOffTime); void dismissLowBatteryWarning(); @@ -486,6 +561,12 @@ public class PowerUI extends SystemUI { void dump(PrintWriter pw); void userSwitched(); + + /** + * Updates the snapshot of battery state used for evaluating battery warnings + * @param snapshot object containing relevant values for making battery warning decisions. + */ + void updateSnapshot(BatteryStateSnapshot snapshot); } // Thermal event received from thermal service manager subsystem 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 a35488518faa..142f398cd881 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -20,9 +20,6 @@ import static com.android.systemui.SysUiServiceProvider.getComponent; import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; - -import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -2956,6 +2953,9 @@ public class NotificationPanelView extends PanelView implements if (mKeyguardStatusBar != null) { mKeyguardStatusBar.dump(fd, pw, args); } + if (mKeyguardStatusView != null) { + mKeyguardStatusView.dump(fd, pw, args); + } } public boolean hasActiveClearableNotifications() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index af3c96f73642..3fa3e1a6e6d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -226,7 +226,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0); return PowerUtil.getBatteryRemainingShortStringFormatted( - mContext, mEstimate.estimateMillis); + mContext, mEstimate.getEstimateMillis()); } private void updateEstimateInBackground() { diff --git a/packages/SystemUI/src/com/android/systemui/volume/Util.java b/packages/SystemUI/src/com/android/systemui/volume/Util.java index c6d62181540e..7edb5a55a9ae 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Util.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Util.java @@ -16,52 +16,13 @@ package com.android.systemui.volume; -import android.content.Context; import android.media.AudioManager; -import android.media.MediaMetadata; -import android.media.VolumeProvider; -import android.media.session.MediaController.PlaybackInfo; -import android.media.session.PlaybackState; -import android.telephony.TelephonyManager; import android.view.View; -import android.widget.TextView; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.Objects; /** * Static helpers for the volume dialog. */ -class Util { - - // Note: currently not shown (only used in the text footer) - private static final SimpleDateFormat HMMAA = new SimpleDateFormat("h:mm aa", Locale.US); - - private static int[] AUDIO_MANAGER_FLAGS = new int[] { - AudioManager.FLAG_SHOW_UI, - AudioManager.FLAG_VIBRATE, - AudioManager.FLAG_PLAY_SOUND, - AudioManager.FLAG_ALLOW_RINGER_MODES, - AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE, - AudioManager.FLAG_SHOW_VIBRATE_HINT, - AudioManager.FLAG_SHOW_SILENT_HINT, - AudioManager.FLAG_FROM_KEY, - AudioManager.FLAG_SHOW_UI_WARNINGS, - }; - - private static String[] AUDIO_MANAGER_FLAG_NAMES = new String[] { - "SHOW_UI", - "VIBRATE", - "PLAY_SOUND", - "ALLOW_RINGER_MODES", - "REMOVE_SOUND_AND_VIBRATE", - "SHOW_VIBRATE_HINT", - "SHOW_SILENT_HINT", - "FROM_KEY", - "SHOW_UI_WARNINGS", - }; +class Util extends com.android.settingslib.volume.Util { public static String logTag(Class<?> c) { final String tag = "vol." + c.getSimpleName(); @@ -70,106 +31,19 @@ class Util { public static String ringerModeToString(int ringerMode) { switch (ringerMode) { - case AudioManager.RINGER_MODE_SILENT: return "RINGER_MODE_SILENT"; - case AudioManager.RINGER_MODE_VIBRATE: return "RINGER_MODE_VIBRATE"; - case AudioManager.RINGER_MODE_NORMAL: return "RINGER_MODE_NORMAL"; - default: return "RINGER_MODE_UNKNOWN_" + ringerMode; - } - } - - public static String mediaMetadataToString(MediaMetadata metadata) { - if (metadata == null) return null; - return metadata.getDescription().toString(); - } - - public static String playbackInfoToString(PlaybackInfo info) { - if (info == null) return null; - final String type = playbackInfoTypeToString(info.getPlaybackType()); - final String vc = volumeProviderControlToString(info.getVolumeControl()); - return String.format("PlaybackInfo[vol=%s,max=%s,type=%s,vc=%s],atts=%s", - info.getCurrentVolume(), info.getMaxVolume(), type, vc, info.getAudioAttributes()); - } - - public static String playbackInfoTypeToString(int type) { - switch (type) { - case PlaybackInfo.PLAYBACK_TYPE_LOCAL: return "LOCAL"; - case PlaybackInfo.PLAYBACK_TYPE_REMOTE: return "REMOTE"; - default: return "UNKNOWN_" + type; - } - } - - public static String playbackStateStateToString(int state) { - switch (state) { - case PlaybackState.STATE_NONE: return "STATE_NONE"; - case PlaybackState.STATE_STOPPED: return "STATE_STOPPED"; - case PlaybackState.STATE_PAUSED: return "STATE_PAUSED"; - case PlaybackState.STATE_PLAYING: return "STATE_PLAYING"; - default: return "UNKNOWN_" + state; - } - } - - public static String volumeProviderControlToString(int control) { - switch (control) { - case VolumeProvider.VOLUME_CONTROL_ABSOLUTE: return "VOLUME_CONTROL_ABSOLUTE"; - case VolumeProvider.VOLUME_CONTROL_FIXED: return "VOLUME_CONTROL_FIXED"; - case VolumeProvider.VOLUME_CONTROL_RELATIVE: return "VOLUME_CONTROL_RELATIVE"; - default: return "VOLUME_CONTROL_UNKNOWN_" + control; - } - } - - public static String playbackStateToString(PlaybackState playbackState) { - if (playbackState == null) return null; - return playbackStateStateToString(playbackState.getState()) + " " + playbackState; - } - - public static String audioManagerFlagsToString(int value) { - return bitFieldToString(value, AUDIO_MANAGER_FLAGS, AUDIO_MANAGER_FLAG_NAMES); - } - - private static String bitFieldToString(int value, int[] values, String[] names) { - if (value == 0) return ""; - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < values.length; i++) { - if ((value & values[i]) != 0) { - if (sb.length() > 0) sb.append(','); - sb.append(names[i]); - } - value &= ~values[i]; - } - if (value != 0) { - if (sb.length() > 0) sb.append(','); - sb.append("UNKNOWN_").append(value); + case AudioManager.RINGER_MODE_SILENT: + return "RINGER_MODE_SILENT"; + case AudioManager.RINGER_MODE_VIBRATE: + return "RINGER_MODE_VIBRATE"; + case AudioManager.RINGER_MODE_NORMAL: + return "RINGER_MODE_NORMAL"; + default: + return "RINGER_MODE_UNKNOWN_" + ringerMode; } - return sb.toString(); - } - - public static String getShortTime(long millis) { - return HMMAA.format(new Date(millis)); - } - - private static CharSequence emptyToNull(CharSequence str) { - return str == null || str.length() == 0 ? null : str; - } - - public static boolean setText(TextView tv, CharSequence text) { - if (Objects.equals(emptyToNull(tv.getText()), emptyToNull(text))) return false; - tv.setText(text); - return true; } public static final void setVisOrGone(View v, boolean vis) { if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return; v.setVisibility(vis ? View.VISIBLE : View.GONE); } - - public static final void setVisOrInvis(View v, boolean vis) { - if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return; - v.setVisibility(vis ? View.VISIBLE : View.INVISIBLE); - } - - public static boolean isVoiceCapable(Context context) { - final TelephonyManager telephony = - (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - return telephony != null && telephony.isVoiceCapable(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index 32bc01cdfdfe..4c16297154f3 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -53,6 +53,7 @@ import android.util.Log; import android.view.accessibility.AccessibilityManager; import com.android.internal.annotations.GuardedBy; +import com.android.settingslib.volume.MediaSessions; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java index 5876ae1910be..58c931190c83 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.verify; import android.app.Notification; import android.app.NotificationManager; +import android.os.BatteryManager; import android.test.suitebuilder.annotation.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -57,6 +58,9 @@ public class PowerNotificationWarningsTest extends SysuiTestCase { // Test Instance. mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager); mPowerNotificationWarnings = new PowerNotificationWarnings(mContext); + BatteryStateSnapshot snapshot = new BatteryStateSnapshot(100, false, false, 1, + BatteryManager.BATTERY_HEALTH_GOOD, 5, 15); + mPowerNotificationWarnings.updateSnapshot(snapshot); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java index 0aed63d25112..f51e4731a390 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java @@ -17,8 +17,7 @@ package com.android.systemui.power; import static android.provider.Settings.Global.SHOW_TEMPERATURE_WARNING; import static android.provider.Settings.Global.SHOW_USB_TEMPERATURE_ALARM; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.anyObject; @@ -29,7 +28,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.Intent; import android.os.BatteryManager; import android.os.IThermalEventListener; import android.os.IThermalService; @@ -42,22 +40,20 @@ import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableResources; -import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.power.PowerUI.WarningsUI; import com.android.systemui.statusbar.phone.StatusBar; +import java.time.Duration; +import java.util.concurrent.TimeUnit; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.time.Duration; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest @@ -75,6 +71,7 @@ public class PowerUITest extends SysuiTestCase { private static final int OLD_BATTERY_LEVEL_NINE = 9; private static final int OLD_BATTERY_LEVEL_10 = 10; private static final long VERY_BELOW_SEVERE_HYBRID_THRESHOLD = TimeUnit.MINUTES.toMillis(15); + public static final int BATTERY_LEVEL_10 = 10; private WarningsUI mMockWarnings; private PowerUI mPowerUI; private EnhancedEstimates mEnhancedEstimates; @@ -176,368 +173,333 @@ public class PowerUITest extends SysuiTestCase { } @Test - public void testShouldShowLowBatteryWarning_showHybridOnly_overrideThresholdHigh_returnsNoShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()) - .thenReturn(Duration.ofHours(1).toMillis()); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); + public void testMaybeShowHybridWarning() { mPowerUI.start(); - // unplugged device that would not show the non-hybrid notification but would show the - // hybrid but the threshold has been overriden to be too low - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertFalse(shouldShow); - } + // verify low warning shown this cycle noticed + BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); + BatteryStateSnapshot lastState = state.get(); + state.mTimeRemainingMillis = Duration.ofHours(2).toMillis(); + state.mBatteryLevel = 15; - @Test - public void testShouldShowLowBatteryWarning_showHybridOnly_overrideThresholdHigh_returnsShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()) - .thenReturn(Duration.ofHours(5).toMillis()); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - mPowerUI.start(); + mPowerUI.maybeShowHybridWarning(state.get(), lastState); - // unplugged device that would not show the non-hybrid notification but would show the - // hybrid since the threshold has been overriden to be much higher - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertTrue(shouldShow); - } + assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isTrue(); + assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isFalse(); - @Test - public void testShouldShowLowBatteryWarning_showHybridOnly_returnsShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - mPowerUI.start(); + // verify severe warning noticed this cycle + lastState = state.get(); + state.mBatteryLevel = 1; + state.mTimeRemainingMillis = Duration.ofMinutes(10).toMillis(); - // unplugged device that would not show the non-hybrid notification but would show the - // hybrid - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertTrue(shouldShow); - } + mPowerUI.maybeShowHybridWarning(state.get(), lastState); - @Test - public void testShouldShowLowBatteryWarning_showHybrid_showStandard_returnsShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - mPowerUI.mBatteryLevel = 10; - mPowerUI.start(); + assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isTrue(); + assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isTrue(); - // unplugged device that would show the non-hybrid notification and the hybrid - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertTrue(shouldShow); - } + // verify getting past threshold resets values + lastState = state.get(); + state.mBatteryLevel = 100; + state.mTimeRemainingMillis = Duration.ofDays(1).toMillis(); - @Test - public void testShouldShowLowBatteryWarning_showStandardOnly_returnsShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - mPowerUI.mBatteryLevel = 10; - mPowerUI.start(); + mPowerUI.maybeShowHybridWarning(state.get(), lastState); - // unplugged device that would show the non-hybrid but not the hybrid - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertTrue(shouldShow); + assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isFalse(); + assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isFalse(); } @Test - public void testShouldShowLowBatteryWarning_deviceHighBattery_returnsNoShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); + public void testShouldShowHybridWarning_lowLevelWarning() { mPowerUI.start(); - - // unplugged device that would show the neither due to battery level being good - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertFalse(shouldShow); + mPowerUI.mLowWarningShownThisChargeCycle = false; + mPowerUI.mSevereWarningShownThisChargeCycle = false; + BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); + + // sanity check to make sure we can show for a valid config + state.mBatteryLevel = 10; + state.mTimeRemainingMillis = Duration.ofHours(2).toMillis(); + boolean shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // Shouldn't show if plugged in + state.mPlugged = true; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + // Shouldn't show if battery is unknown + state.mPlugged = false; + state.mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + state.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD; + // Already shown both warnings + mPowerUI.mLowWarningShownThisChargeCycle = true; + mPowerUI.mSevereWarningShownThisChargeCycle = true; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + // Can show low warning + mPowerUI.mLowWarningShownThisChargeCycle = false; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // Can't show if above the threshold for time & battery + state.mTimeRemainingMillis = Duration.ofHours(1000).toMillis(); + state.mBatteryLevel = 100; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + // Battery under low percentage threshold but not time + state.mBatteryLevel = 10; + state.mLowLevelThreshold = 50; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // Should also trigger if both level and time remaining under low threshold + state.mTimeRemainingMillis = Duration.ofHours(2).toMillis(); + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // battery saver should block the low level warning though + state.mIsPowerSaver = true; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); } @Test - public void testShouldShowLowBatteryWarning_devicePlugged_returnsNoShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - mPowerUI.start(); - - // plugged device that would show the neither due to being plugged - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(!UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertFalse(shouldShow); - } - - @Test - public void testShouldShowLowBatteryWarning_deviceBatteryStatusUnknown_returnsNoShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); + public void testShouldShowHybridWarning_severeLevelWarning() { mPowerUI.start(); - - // Unknown battery status device that would show the neither due to the battery status being - // unknown - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, - !POWER_SAVER_OFF, BatteryManager.BATTERY_STATUS_UNKNOWN); - assertFalse(shouldShow); + mPowerUI.mLowWarningShownThisChargeCycle = false; + mPowerUI.mSevereWarningShownThisChargeCycle = false; + BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); + + // sanity check to make sure we can show for a valid config + state.mBatteryLevel = 1; + state.mTimeRemainingMillis = Duration.ofMinutes(1).toMillis(); + boolean shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // Shouldn't show if plugged in + state.mPlugged = true; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + // Shouldn't show if battery is unknown + state.mPlugged = false; + state.mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + state.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD; + // Already shown both warnings + mPowerUI.mLowWarningShownThisChargeCycle = true; + mPowerUI.mSevereWarningShownThisChargeCycle = true; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + // Can show severe warning + mPowerUI.mSevereWarningShownThisChargeCycle = false; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // Can't show if above the threshold for time & battery + state.mTimeRemainingMillis = Duration.ofHours(1000).toMillis(); + state.mBatteryLevel = 100; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isFalse(); + + // Battery under low percentage threshold but not time + state.mBatteryLevel = 1; + state.mSevereLevelThreshold = 5; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // Should also trigger if both level and time remaining under low threshold + state.mTimeRemainingMillis = Duration.ofHours(2).toMillis(); + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); + + // battery saver should not block the severe level warning though + state.mIsPowerSaver = true; + shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); + assertThat(shouldShow).isTrue(); } @Test - public void testShouldShowLowBatteryWarning_batterySaverEnabled_returnsNoShow() { - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); + public void testShouldDismissHybridWarning() { mPowerUI.start(); - - // BatterySaverEnabled device that would show the neither due to battery saver - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, - !POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertFalse(shouldShow); + BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); + + // We should dismiss if the device is plugged in + state.mPlugged = true; + state.mTimeRemainingMillis = Duration.ofHours(1).toMillis(); + state.mLowThresholdMillis = Duration.ofHours(2).toMillis(); + boolean shouldDismiss = mPowerUI.shouldDismissHybridWarning(state.get()); + assertThat(shouldDismiss).isTrue(); + + // If not plugged in and below the threshold we should not dismiss + state.mPlugged = false; + shouldDismiss = mPowerUI.shouldDismissHybridWarning(state.get()); + assertThat(shouldDismiss).isFalse(); + + // If we go over the low warning threshold we should dismiss + state.mTimeRemainingMillis = Duration.ofHours(3).toMillis(); + shouldDismiss = mPowerUI.shouldDismissHybridWarning(state.get()); + assertThat(shouldDismiss).isTrue(); } @Test - public void testShouldShowLowBatteryWarning_onlyShowsOncePerChargeCycle() { + public void testRefreshEstimateIfNeeded_onlyQueriesEstimateOnBatteryLevelChangeOrNull() { mPowerUI.start(); + Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true); when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - when(mEnhancedEstimates.getEstimate()) - .thenReturn(new Estimate(BELOW_HYBRID_THRESHOLD, true)); - mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD; - - mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_NINE, UNPLUGGED, UNPLUGGED, - ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET); - - // reduce battery level to handle time based trigger -> level trigger interactions + when(mEnhancedEstimates.getEstimate()).thenReturn(estimate); mPowerUI.mBatteryLevel = 10; - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertFalse(shouldShow); - } - - @Test - public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabledLegacy() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(false); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - // device that gets power saver turned on should dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET, - BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, !POWER_SAVER_OFF); - assertTrue(shouldDismiss); - } - @Test - public void testShouldNotDismissLowBatteryWarning_dismissWhenPowerSaverEnabledHybrid() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - // device that gets power saver turned on should dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET, - BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, !POWER_SAVER_OFF); - assertFalse(shouldDismiss); - } - - @Test - public void testShouldDismissLowBatteryWarning_dismissWhenPlugged() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - // device that gets plugged in should dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(!UNPLUGGED, BELOW_WARNING_BUCKET, - BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF); - assertTrue(shouldDismiss); - } - - @Test - public void testShouldDismissLowBatteryWarning_dismissHybridSignal_showStandardSignal_shouldShow() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - // would dismiss hybrid but not non-hybrid should not dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET, - BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF); - assertFalse(shouldDismiss); - } - - @Test - public void testShouldDismissLowBatteryWarning_showHybridSignal_dismissStandardSignal_shouldShow() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - // would dismiss non-hybrid but not hybrid should not dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, POWER_SAVER_OFF); - assertFalse(shouldDismiss); - } - - @Test - public void testShouldDismissLowBatteryWarning_showBothSignal_shouldShow() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - // should not dismiss when both would not dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET, - BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD, POWER_SAVER_OFF); - assertFalse(shouldDismiss); - } - - @Test - public void testShouldDismissLowBatteryWarning_dismissBothSignal_shouldDismiss() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - //should dismiss if both would dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF); - assertTrue(shouldDismiss); - } - - @Test - public void testShouldDismissLowBatteryWarning_dismissStandardSignal_hybridDisabled_shouldDismiss() { - mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(false); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - - // would dismiss non-hybrid with hybrid disabled should dismiss - boolean shouldDismiss = - mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, POWER_SAVER_OFF); - assertTrue(shouldDismiss); - } - - @Test - public void testShouldDismissLowBatteryWarning_powerSaverModeEnabled() - throws InterruptedException { - when(mPowerManager.isPowerSaveMode()).thenReturn(true); - - mPowerUI.start(); - mPowerUI.mReceiver.onReceive(mContext, - new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); - - CountDownLatch latch = new CountDownLatch(1); - ThreadUtils.postOnBackgroundThread(() -> latch.countDown()); - latch.await(5, TimeUnit.SECONDS); - - verify(mMockWarnings).dismissLowBatteryWarning(); - } - - @Test - public void testShouldNotDismissLowBatteryWarning_powerSaverModeDisabled() - throws InterruptedException { - when(mPowerManager.isPowerSaveMode()).thenReturn(false); - - mPowerUI.start(); - mPowerUI.mReceiver.onReceive(mContext, - new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); - - CountDownLatch latch = new CountDownLatch(1); - ThreadUtils.postOnBackgroundThread(() -> latch.countDown()); - latch.await(5, TimeUnit.SECONDS); + // we expect that the first time it will query since there is no last battery snapshot. + // However an invalid estimate (-1) is returned. + Estimate refreshedEstimate = mPowerUI.refreshEstimateIfNeeded(); + assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD); + BatteryStateSnapshot snapshot = new BatteryStateSnapshot( + BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, + 0, 0, -1, 0, 0, false); + mPowerUI.mLastBatteryStateSnapshot = snapshot; + + // query again since the estimate was -1 + estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true); + when(mEnhancedEstimates.getEstimate()).thenReturn(estimate); + refreshedEstimate = mPowerUI.refreshEstimateIfNeeded(); + assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD); + snapshot = new BatteryStateSnapshot( + BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, 0, + 0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false); + mPowerUI.mLastBatteryStateSnapshot = snapshot; + + // Battery level hasn't changed, so we don't query again + estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true); + when(mEnhancedEstimates.getEstimate()).thenReturn(estimate); + refreshedEstimate = mPowerUI.refreshEstimateIfNeeded(); + assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD); - verify(mMockWarnings, never()).dismissLowBatteryWarning(); + // Battery level changes so we update again + mPowerUI.mBatteryLevel = 9; + refreshedEstimate = mPowerUI.refreshEstimateIfNeeded(); + assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD); } @Test - public void testSevereWarning_countsAsLowAndSevere_WarningOnlyShownOnce() { + public void testShouldShowStandardWarning() { mPowerUI.start(); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - when(mEnhancedEstimates.getEstimate()) - .thenReturn(new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true)); - mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD; - - // reduce battery level to handle time based trigger -> level trigger interactions - mPowerUI.mBatteryLevel = 5; - boolean shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, BELOW_SEVERE_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertTrue(shouldShow); - - // actually run the end to end since it handles changing the internal state. - mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_10, UNPLUGGED, UNPLUGGED, - ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET); - - shouldShow = - mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET, - ABOVE_WARNING_BUCKET, VERY_BELOW_SEVERE_HYBRID_THRESHOLD, - POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD); - assertFalse(shouldShow); + BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); + state.mIsHybrid = false; + BatteryStateSnapshot lastState = state.get(); + + // sanity check to make sure we can show for a valid config + state.mBatteryLevel = 10; + state.mBucket = -1; + boolean shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isTrue(); + lastState = state.get(); + + // Shouldn't show if plugged in + state.mPlugged = true; + shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isFalse(); + + state.mPlugged = false; + // Shouldn't show if battery saver + state.mIsPowerSaver = true; + shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isFalse(); + + state.mIsPowerSaver = false; + // Shouldn't show if battery is unknown + state.mPlugged = false; + state.mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; + shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isFalse(); + + state.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD; + // show if plugged -> unplugged, bucket -1 -> -1 + state.mPlugged = true; + state.mBucket = -1; + lastState = state.get(); + state.mPlugged = false; + state.mBucket = -1; + shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isTrue(); + + // don't show if plugged -> unplugged, bucket 0 -> 0 + state.mPlugged = true; + state.mBucket = 0; + lastState = state.get(); + state.mPlugged = false; + state.mBucket = 0; + shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isFalse(); + + // show if unplugged -> unplugged, bucket 0 -> -1 + state.mPlugged = false; + state.mBucket = 0; + lastState = state.get(); + state.mPlugged = false; + state.mBucket = -1; + shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isTrue(); + + // don't show if unplugged -> unplugged, bucket -1 -> 1 + state.mPlugged = false; + state.mBucket = -1; + lastState = state.get(); + state.mPlugged = false; + state.mBucket = 1; + shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); + assertThat(shouldShow).isFalse(); } @Test - public void testMaybeShowBatteryWarning_onlyQueriesEstimateOnBatteryLevelChangeOrNull() { + public void testShouldDismissStandardWarning() { mPowerUI.start(); - Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true); - when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); - when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); - when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); - when(mEnhancedEstimates.getEstimate()).thenReturn(estimate); - mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD; - - // we expect that the first time it will query even if the level is the same - mPowerUI.mBatteryLevel = 9; - mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_NINE, UNPLUGGED, UNPLUGGED, - ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET); - verify(mEnhancedEstimates, times(1)).getEstimate(); - - // We should NOT query again if the battery level hasn't changed - mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_NINE, UNPLUGGED, UNPLUGGED, - ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET); - verify(mEnhancedEstimates, times(1)).getEstimate(); - - // Battery level has changed, so we should query again - mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_10, UNPLUGGED, UNPLUGGED, - ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET); - verify(mEnhancedEstimates, times(2)).getEstimate(); + BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); + state.mIsHybrid = false; + BatteryStateSnapshot lastState = state.get(); + + // should dismiss if battery saver + state.mIsPowerSaver = true; + boolean shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState); + assertThat(shouldDismiss).isTrue(); + + state.mIsPowerSaver = false; + // should dismiss if plugged + state.mPlugged = true; + shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState); + assertThat(shouldDismiss).isTrue(); + + state.mPlugged = false; + // should dismiss if bucket 0 -> 1 + state.mBucket = 0; + lastState = state.get(); + state.mBucket = 1; + shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState); + assertThat(shouldDismiss).isTrue(); + + // shouldn't dismiss if bucket -1 -> 0 + state.mBucket = -1; + lastState = state.get(); + state.mBucket = 0; + shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState); + assertThat(shouldDismiss).isFalse(); + + // should dismiss if powersaver & bucket 0 -> 1 + state.mIsPowerSaver = true; + state.mBucket = 0; + lastState = state.get(); + state.mBucket = 1; + shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState); + assertThat(shouldDismiss).isTrue(); } private Temperature getEmergencyStatusTemp(int type, String name) { @@ -556,4 +518,35 @@ public class PowerUITest extends SysuiTestCase { mPowerUI.mComponents = mContext.getComponents(); mPowerUI.mThermalService = mThermalServiceMock; } + + /** + * A simple wrapper class that sets values by default and makes them not final to improve + * test clarity. + */ + private class BatteryStateSnapshotWrapper { + public int mBatteryLevel = 100; + public boolean mIsPowerSaver = false; + public boolean mPlugged = false; + public long mSevereThresholdMillis = Duration.ofHours(1).toMillis(); + public long mLowThresholdMillis = Duration.ofHours(3).toMillis(); + public int mSevereLevelThreshold = 5; + public int mLowLevelThreshold = 15; + public int mBucket = 1; + public int mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD; + public long mTimeRemainingMillis = Duration.ofHours(24).toMillis(); + public boolean mIsBasedOnUsage = true; + public boolean mIsHybrid = true; + + public BatteryStateSnapshot get() { + if (mIsHybrid) { + return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket, + mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold, + mTimeRemainingMillis, mSevereThresholdMillis, mLowThresholdMillis, + mIsBasedOnUsage); + } else { + return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket, + mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold); + } + } + } } diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index ab8ad0f45f9f..91b161d3192f 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -7075,6 +7075,18 @@ message MetricsEvent { // OPEN: Accessibility detail settings (android.settings.ACCESSIBILITY_DETAILS_SETTINGS intent) ACCESSIBILITY_DETAILS_SETTINGS = 1682; + // Open: Settings will show the conditional when Grayscale mode is on + SETTINGS_CONDITION_GRAYSCALE_MODE = 1683; + + // ACTION: Individual contextual card loading time + ACTION_CONTEXTUAL_CARD_LOAD = 1684; + + //ACTION: Contextual card loading timeout + ACTION_CONTEXTUAL_CARD_LOAD_TIMEOUT = 1685; + + //ACTION: Log result for each card's eligibility check + ACTION_CONTEXTUAL_CARD_ELIGIBILITY = 1686; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java index a18686da653e..9b70272ed952 100644 --- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java +++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java @@ -16,6 +16,7 @@ package com.android.server.contentsuggestions; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -73,6 +74,13 @@ public final class ContentSuggestionsPerUserService extends throw new PackageManager.NameNotFoundException( "Could not get service for " + serviceComponent); } + if (!Manifest.permission.BIND_CONTENT_SUGGESTIONS_SERVICE.equals(si.permission)) { + Slog.w(TAG, "ContentSuggestionsService from '" + si.packageName + + "' does not require permission " + + Manifest.permission.BIND_CONTENT_SUGGESTIONS_SERVICE); + throw new SecurityException("Service does not require permission " + + Manifest.permission.BIND_CONTENT_SUGGESTIONS_SERVICE); + } return si; } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d2c39eaeafb7..da89116792ab 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1575,8 +1575,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public boolean isActiveNetworkMetered() { enforceAccessPermission(); - final int uid = Binder.getCallingUid(); - final NetworkCapabilities caps = getUnfilteredActiveNetworkState(uid).networkCapabilities; + final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork()); if (caps != null) { return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } else { diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index 18c272202990..d26663520850 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -38,9 +38,11 @@ import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.server.am.SettingsToPropertiesMapper; import com.android.server.utils.FlagNamespaceUtils; import java.io.File; +import java.util.Arrays; /** * Utilities to help rescue the system from crash loops. Callers are expected to @@ -158,6 +160,7 @@ public class RescueParty { * opportunity to reset any settings depending on our rescue level. */ public static void onSettingsProviderPublished(Context context) { + handleNativeRescuePartyResets(); executeRescueLevel(context); } @@ -176,6 +179,13 @@ public class RescueParty { return SystemClock.elapsedRealtime(); } + private static void handleNativeRescuePartyResets() { + if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) { + FlagNamespaceUtils.resetDeviceConfig(Settings.RESET_MODE_TRUSTED_DEFAULTS, + Arrays.asList(SettingsToPropertiesMapper.getResetNativeCategories())); + } + } + /** * Escalate to the next rescue level. After incrementing the level you'll * probably want to call {@link #executeRescueLevel(Context)}. diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 415a8927295d..f9fcef68381e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -27,6 +27,8 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfig.OnPropertyChangedListener; import android.provider.Settings; import android.text.TextUtils; +import android.text.TextUtils.SimpleStringSplitter; +import android.util.ArraySet; import android.util.KeyValueListParser; import android.util.Slog; @@ -235,6 +237,8 @@ final class ActivityManagerConstants extends ContentObserver { // Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED volatile boolean mFlagBackgroundActivityStartsEnabled; + volatile ArraySet<String> mPackageNamesWhitelistedForBgActivityStarts = new ArraySet<>(); + private final ActivityManagerService mService; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -273,6 +277,10 @@ final class ActivityManagerConstants extends ContentObserver { Settings.Global.getUriFor( Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED); + private static final Uri BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI = + Settings.Global.getUriFor( + Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST); + private final OnPropertyChangedListener mOnDeviceConfigChangedListener = new OnPropertyChangedListener() { @Override @@ -293,9 +301,12 @@ final class ActivityManagerConstants extends ContentObserver { mResolver.registerContentObserver(ACTIVITY_MANAGER_CONSTANTS_URI, false, this); mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this); mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_ENABLED_URI, false, this); + mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI, + false, this); updateConstants(); updateActivityStartsLoggingEnabled(); updateBackgroundActivityStartsEnabled(); + updateBackgroundActivityStartsPackageNamesWhitelist(); DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ActivityThread.currentApplication().getMainExecutor(), mOnDeviceConfigChangedListener); @@ -325,6 +336,8 @@ final class ActivityManagerConstants extends ContentObserver { updateActivityStartsLoggingEnabled(); } else if (BACKGROUND_ACTIVITY_STARTS_ENABLED_URI.equals(uri)) { updateBackgroundActivityStartsEnabled(); + } else if (BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI.equals(uri)) { + updateBackgroundActivityStartsPackageNamesWhitelist(); } } @@ -414,6 +427,21 @@ final class ActivityManagerConstants extends ContentObserver { Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, 1) == 1; } + private void updateBackgroundActivityStartsPackageNamesWhitelist() { + final String setting = Settings.Global.getString(mResolver, + Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST); + if (TextUtils.isEmpty(setting)) { + return; + } + ArraySet<String> newSet = new ArraySet<>(); + SimpleStringSplitter splitter = new SimpleStringSplitter(':'); + splitter.setString(setting); + while (splitter.hasNext()) { + newSet.add(splitter.next()); + } + mPackageNamesWhitelistedForBgActivityStarts = newSet; + } + private void updateMaxCachedProcesses() { String maxCachedProcessesFlag = DeviceConfig.getProperty( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MAX_CACHED_PROCESSES); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ccb9d82571f7..0a68ce0adf28 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -17862,6 +17862,10 @@ public class ActivityManagerService extends IActivityManager.Stub return mConstants.mFlagActivityStartsLoggingEnabled; } + public boolean isPackageNameWhitelistedForBgActivityStarts(String packageName) { + return mConstants.mPackageNamesWhitelistedForBgActivityStarts.contains(packageName); + } + public boolean isBackgroundActivityStartsEnabled() { return mConstants.mFlagBackgroundActivityStartsEnabled; } diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index 8e2ca0691277..34fca23ccb9e 100644 --- a/services/core/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java @@ -81,7 +81,9 @@ final class BroadcastFilter extends IntentFilter { StringBuilder sb = new StringBuilder(); sb.append("BroadcastFilter{"); sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" u"); + sb.append(' '); + sb.append(owningUid); + sb.append("/u"); sb.append(owningUserId); sb.append(' '); sb.append(receiverList); diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index efb1c445925f..c1ed54e647d7 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -445,7 +445,7 @@ public final class BroadcastQueue { final long elapsed = finishTime - r.receiverTime; r.state = BroadcastRecord.IDLE; if (state == BroadcastRecord.IDLE) { - Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE"); + Slog.w(TAG_BROADCAST, "finishReceiver [" + mQueueName + "] called but state is IDLE"); } if (r.allowBackgroundActivityStarts && r.curApp != null) { if (elapsed > mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT) { @@ -478,12 +478,13 @@ public final class BroadcastQueue { if (!r.timeoutExempt) { if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) { if (DEBUG_BROADCAST_DEFERRAL) { - Slog.i(TAG, "Broadcast receiver was slow: " + receiver + " br=" + r); + Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1) + + " was slow: " + receiver + " br=" + r); } if (r.curApp != null) { mDispatcher.startDeferring(r.curApp.uid); } else { - Slog.d(TAG, "finish receiver curApp is null? " + r); + Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r); } } } else { @@ -796,9 +797,7 @@ public final class BroadcastQueue { skipReceiverLocked(r); } } else { - if (r.receiverTime == 0) { - r.receiverTime = SystemClock.uptimeMillis(); - } + r.receiverTime = SystemClock.uptimeMillis(); maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r); performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, @@ -1083,16 +1082,19 @@ public final class BroadcastQueue { if (newCount == 0) { // done! clear out this record's bookkeeping and deliver if (DEBUG_BROADCAST_DEFERRAL) { - Slog.i(TAG, "Sending broadcast completion for split token " - + r.splitToken); + Slog.i(TAG_BROADCAST, + "Sending broadcast completion for split token " + + r.splitToken + " : " + r.intent.getAction()); } mSplitRefcounts.delete(r.splitToken); } else { // still have some split broadcast records in flight; update refcount // and hold off on the callback if (DEBUG_BROADCAST_DEFERRAL) { - Slog.i(TAG, "Result refcount " + newCount + " for split token " - + r.splitToken + " - not sending completion yet"); + Slog.i(TAG_BROADCAST, + "Result refcount now " + newCount + " for split token " + + r.splitToken + " : " + r.intent.getAction() + + " - not sending completion yet"); } sendResult = false; mSplitRefcounts.put(r.splitToken, newCount); @@ -1155,7 +1157,7 @@ public final class BroadcastQueue { BroadcastRecord defer; if (r.nextReceiver + 1 == numReceivers) { if (DEBUG_BROADCAST_DEFERRAL) { - Slog.i(TAG, "Sole receiver of " + r + Slog.i(TAG_BROADCAST, "Sole receiver of " + r + " is under deferral; setting aside and proceeding"); } defer = r; @@ -1185,15 +1187,25 @@ public final class BroadcastQueue { // first split of this record; refcount for 'r' and 'deferred' r.splitToken = defer.splitToken = nextSplitTokenLocked(); mSplitRefcounts.put(r.splitToken, 2); + if (DEBUG_BROADCAST_DEFERRAL) { + Slog.i(TAG_BROADCAST, + "Broadcast needs split refcount; using new token " + + r.splitToken); + } } else { // new split from an already-refcounted situation; increment count final int curCount = mSplitRefcounts.get(token); if (DEBUG_BROADCAST_DEFERRAL) { if (curCount == 0) { - Slog.wtf(TAG, "Split refcount is zero with token for " + r); + Slog.wtf(TAG_BROADCAST, + "Split refcount is zero with token for " + r); } } mSplitRefcounts.put(token, curCount + 1); + if (DEBUG_BROADCAST_DEFERRAL) { + Slog.i(TAG_BROADCAST, "New split count for token " + token + + " is " + (curCount + 1)); + } } } } @@ -1529,7 +1541,7 @@ public final class BroadcastQueue { if (skip) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Skipping delivery of ordered [" + mQueueName + "] " - + r + " for whatever reason"); + + r + " for reason described above"); r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED; r.receiver = null; r.curFilter = null; diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index fa9b79d0b158..13525043412e 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -332,7 +332,6 @@ final class BroadcastRecord extends Binder { } splitReceivers.add(o); receivers.remove(i); - break; } else { i++; } @@ -350,6 +349,7 @@ final class BroadcastRecord extends Binder { resultData, resultExtras, ordered, sticky, initialSticky, userId, allowBackgroundActivityStarts, timeoutExempt); + split.splitToken = this.splitToken; return split; } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 894a704c5bba..194549f15ecf 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.annotation.NonNull; import android.content.ContentResolver; import android.database.ContentObserver; import android.net.Uri; @@ -78,11 +79,11 @@ public class SettingsToPropertiesMapper { // permission in the corresponding .te file your feature belongs to. @VisibleForTesting static final String[] sDeviceConfigScopes = new String[] { - DeviceConfig.ActivityManagerNativeBoot.NAMESPACE, - DeviceConfig.MediaNative.NAMESPACE, + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, + DeviceConfig.NAMESPACE_MEDIA_NATIVE, DeviceConfig.NAMESPACE_NETD_NATIVE, - DeviceConfig.RuntimeNativeBoot.NAMESPACE, + DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, DeviceConfig.RuntimeNative.NAMESPACE, }; @@ -167,7 +168,7 @@ public class SettingsToPropertiesMapper { * booting. * @return */ - public static String[] getResetNativeCategories() { + public static @NonNull String[] getResetNativeCategories() { if (!isNativeFlagsResetPerformed()) { return new String[0]; } diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 280bc026a76e..d723c7b5826d 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -146,7 +146,7 @@ final class HistoricalRegistry { * Whether history is enabled. */ @GuardedBy("mInMemoryLock") - private int mMode = AppOpsManager.HISTORICAL_MODE_DISABLED; + private int mMode = AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE; /** * This granularity has been chosen to allow clean delineation for intervals diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 9af57daa259b..451fd66d4327 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -201,51 +201,72 @@ import java.util.ArrayList; } } - /*package*/ int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( + private static final class BtDeviceConnectionInfo { + final @NonNull BluetoothDevice mDevice; + final @AudioService.BtProfileConnectionState int mState; + final int mProfile; + final boolean mSupprNoisy; + final int mVolume; + + BtDeviceConnectionInfo(@NonNull BluetoothDevice device, + @AudioService.BtProfileConnectionState int state, + int profile, boolean suppressNoisyIntent, int vol) { + mDevice = device; + mState = state; + mProfile = profile; + mSupprNoisy = suppressNoisyIntent; + mVolume = vol; + } + } + + /*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { - AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( - "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state - // only querying address as this is the only readily available field - // on the device - + " addr=" + device.getAddress() - + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent - + " vol=" + a2dpVolume)).printLog(TAG)); - synchronized (mDeviceStateLock) { - if (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, - new BtHelper.BluetoothA2dpDeviceInfo(device))) { - AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "A2DP connection state ignored")); - return 0; - } - return mDeviceInventory.setBluetoothA2dpDeviceConnectionState( - device, state, profile, suppressNoisyIntent, - AudioSystem.DEVICE_NONE, a2dpVolume); - } + final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile, + suppressNoisyIntent, a2dpVolume); + + // TODO add a check to try to remove unprocessed messages for the same device (the old + // check didn't work), and make sure it doesn't conflict with config change message + sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); } /*package*/ int handleBluetoothA2dpActiveDeviceChange( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { + // FIXME method was added by @a8439e2 but never used, and now conflicts with async behavior + // of handleBluetoothA2dpDeviceConfigChange and + // setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent synchronized (mDeviceStateLock) { return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile, suppressNoisyIntent, a2dpVolume); } } - /*package*/ int setBluetoothHearingAidDeviceConnectionState( + private static final class HearingAidDeviceConnectionInfo { + final @NonNull BluetoothDevice mDevice; + final @AudioService.BtProfileConnectionState int mState; + final boolean mSupprNoisy; + final int mMusicDevice; + final @NonNull String mEventSource; + + HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device, + @AudioService.BtProfileConnectionState int state, + boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) { + mDevice = device; + mState = state; + mSupprNoisy = suppressNoisyIntent; + mMusicDevice = musicDevice; + mEventSource = eventSource; + } + } + + /*package*/ void postBluetoothHearingAidDeviceConnectionState( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) { - AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( - "setHearingAidDeviceConnectionState state=" + state - + " addr=" + device.getAddress() - + " supprNoisy=" + suppressNoisyIntent - + " src=" + eventSource)).printLog(TAG)); - synchronized (mDeviceStateLock) { - return mDeviceInventory.setBluetoothHearingAidDeviceConnectionState( - device, state, suppressNoisyIntent, musicDevice); - } + final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo( + device, state, suppressNoisyIntent, musicDevice, eventSource); + sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); } // never called by system components @@ -766,6 +787,35 @@ import java.util.ArrayList; mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); } break; + case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: { + final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj; + AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( + "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent " + + " state=" + info.mState + // only querying address as this is the only readily available + // field on the device + + " addr=" + info.mDevice.getAddress() + + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy + + " vol=" + info.mVolume)).printLog(TAG)); + synchronized (mDeviceStateLock) { + mDeviceInventory.setBluetoothA2dpDeviceConnectionState( + info.mDevice, info.mState, info.mProfile, info.mSupprNoisy, + AudioSystem.DEVICE_NONE, info.mVolume); + } + } break; + case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: { + final HearingAidDeviceConnectionInfo info = + (HearingAidDeviceConnectionInfo) msg.obj; + AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( + "setHearingAidDeviceConnectionState state=" + info.mState + + " addr=" + info.mDevice.getAddress() + + " supprNoisy=" + info.mSupprNoisy + + " src=" + info.mEventSource)).printLog(TAG)); + synchronized (mDeviceStateLock) { + mDeviceInventory.setBluetoothHearingAidDeviceConnectionState( + info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); + } + } break; default: Log.wtf(TAG, "Invalid message " + msg.what); } @@ -809,6 +859,10 @@ import java.util.ArrayList; private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24; private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25; private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26; + // process external command to (dis)connect an A2DP device + private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 27; + // process external command to (dis)connect a hearing aid device + private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28; private static boolean isMessageHandledUnderWakelock(int msgId) { @@ -821,6 +875,8 @@ import java.util.ArrayList; case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: case MSG_TOGGLE_HDMI: case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: + case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: + case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: return true; default: return false; diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 37f0496c0db3..41a3c9859f23 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -578,7 +578,7 @@ public final class AudioDeviceInventory { return mCurAudioRoutes; } - /*package*/ int setBluetoothA2dpDeviceConnectionState( + /*package*/ void setBluetoothA2dpDeviceConnectionState( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) { int delay; @@ -614,46 +614,50 @@ public final class AudioDeviceInventory { delay); } } - return delay; } /*package*/ int handleBluetoothA2dpActiveDeviceChange( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { - if (state == BluetoothProfile.STATE_DISCONNECTED) { - return setBluetoothA2dpDeviceConnectionState(device, state, profile, - suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume); - } - // state == BluetoothProfile.STATE_CONNECTED - synchronized (mConnectedDevices) { - for (int i = 0; i < mConnectedDevices.size(); i++) { - final DeviceInfo deviceInfo = mConnectedDevices.valueAt(i); - if (deviceInfo.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { - continue; - } - // If A2DP device exists, this is either an active device change or - // device config change - final String existingDevicekey = mConnectedDevices.keyAt(i); - final String deviceName = device.getName(); - final String address = device.getAddress(); - final String newDeviceKey = DeviceInfo.makeDeviceListKey( - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address); - int a2dpCodec = mDeviceBroker.getA2dpCodec(device); - // Device not equal to existing device, active device change - if (!TextUtils.equals(existingDevicekey, newDeviceKey)) { - mConnectedDevices.remove(existingDevicekey); - mConnectedDevices.put(newDeviceKey, new DeviceInfo( - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName, - address, a2dpCodec)); - mDeviceBroker.postA2dpActiveDeviceChange( - new BtHelper.BluetoothA2dpDeviceInfo( - device, a2dpVolume, a2dpCodec)); - return 0; - } else { - // Device config change for existing device - mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device); - return 0; + // method was added by QC but never used, and now conflicts with async behavior of + // handleBluetoothA2dpDeviceConfigChange and + // setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent + if (false) { + if (state == BluetoothProfile.STATE_DISCONNECTED) { + setBluetoothA2dpDeviceConnectionState(device, state, profile, + suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume); + } + // state == BluetoothProfile.STATE_CONNECTED + synchronized (mConnectedDevices) { + for (int i = 0; i < mConnectedDevices.size(); i++) { + final DeviceInfo deviceInfo = mConnectedDevices.valueAt(i); + if (deviceInfo.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { + continue; + } + // If A2DP device exists, this is either an active device change or + // device config change + final String existingDevicekey = mConnectedDevices.keyAt(i); + final String deviceName = device.getName(); + final String address = device.getAddress(); + final String newDeviceKey = DeviceInfo.makeDeviceListKey( + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address); + int a2dpCodec = mDeviceBroker.getA2dpCodec(device); + // Device not equal to existing device, active device change + if (!TextUtils.equals(existingDevicekey, newDeviceKey)) { + mConnectedDevices.remove(existingDevicekey); + mConnectedDevices.put(newDeviceKey, new DeviceInfo( + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName, + address, a2dpCodec)); + mDeviceBroker.postA2dpActiveDeviceChange( + new BtHelper.BluetoothA2dpDeviceInfo( + device, a2dpVolume, a2dpCodec)); + return 0; + } else { + // Device config change for existing device + mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device); + return 0; + } } } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6bd412bcd536..91d19def1766 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4041,7 +4041,10 @@ public class AudioService extends IAudioService.Stub @Retention(RetentionPolicy.SOURCE) public @interface BtProfileConnectionState {} - public int setBluetoothHearingAidDeviceConnectionState( + /** + * See AudioManager.setBluetoothHearingAidDeviceConnectionState() + */ + public void setBluetoothHearingAidDeviceConnectionState( @NonNull BluetoothDevice device, @BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice) { @@ -4053,14 +4056,14 @@ public class AudioService extends IAudioService.Stub throw new IllegalArgumentException("Illegal BluetoothProfile state for device " + " (dis)connection, got " + state); } - return mDeviceBroker.setBluetoothHearingAidDeviceConnectionState( + mDeviceBroker.postBluetoothHearingAidDeviceConnectionState( device, state, suppressNoisyIntent, musicDevice, "AudioService"); } /** * See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() */ - public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( + public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { if (device == null) { @@ -4071,7 +4074,7 @@ public class AudioService extends IAudioService.Stub throw new IllegalArgumentException("Illegal BluetoothProfile state for device " + " (dis)connection, got " + state); } - return mDeviceBroker.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, state, + mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, state, profile, suppressNoisyIntent, a2dpVolume); } @@ -4094,6 +4097,9 @@ public class AudioService extends IAudioService.Stub public int handleBluetoothA2dpActiveDeviceChange( BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { + // FIXME method was added by @a8439e2 but never used, and now conflicts with async behavior + // of handleBluetoothA2dpDeviceConfigChange and + // setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent if (device == null) { throw new IllegalArgumentException("Illegal null device"); } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 58c1882abf6f..04073cb5f45c 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -426,7 +426,7 @@ public class BtHelper { final BluetoothDevice btDevice = deviceList.get(0); final @BluetoothProfile.BtProfileState int state = mHearingAid.getConnectionState(btDevice); - mDeviceBroker.setBluetoothHearingAidDeviceConnectionState( + mDeviceBroker.postBluetoothHearingAidDeviceConnectionState( btDevice, state, /*suppressNoisyIntent*/ false, /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE, diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index e9ae516cc8d0..9882f6c0d4c1 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -138,9 +138,19 @@ abstract class DisplayDevice { } /** - * Sets the mode, if supported. + * Sets the display modes the system is allowed to switch between, roughly ordered by + * preference. + * + * Not all display devices will automatically switch between modes, so it's important that the + * most-desired modes are at the beginning of the allowed array. + */ + public void setAllowedDisplayModesLocked(int[] modes) { + } + + /** + * Sets the requested color mode. */ - public void requestDisplayModesLocked(int colorMode, int modeId) { + public void setRequestedColorModeLocked(int colorMode) { } public void onOverlayChangedLocked() { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 6c00da20b91e..32f34b8378ce 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -167,13 +167,13 @@ public final class DisplayManagerService extends SystemService { private static final int MSG_DELIVER_DISPLAY_EVENT = 3; private static final int MSG_REQUEST_TRAVERSAL = 4; private static final int MSG_UPDATE_VIEWPORT = 5; - private static final int MSG_REGISTER_BRIGHTNESS_TRACKER = 6; - private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 7; + private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 6; private final Context mContext; private final DisplayManagerHandler mHandler; private final Handler mUiHandler; private final DisplayAdapterListener mDisplayAdapterListener; + private final DisplayModeDirector mDisplayModeDirector; private WindowManagerInternal mWindowManagerInternal; private InputManagerInternal mInputManagerInternal; private IMediaProjectionManager mProjectionService; @@ -310,6 +310,7 @@ public final class DisplayManagerService extends SystemService { mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayAdapterListener = new DisplayAdapterListener(); + mDisplayModeDirector = new DisplayModeDirector(context, mHandler); mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); Resources resources = mContext.getResources(); mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger( @@ -322,7 +323,7 @@ public final class DisplayManagerService extends SystemService { mMinimumBrightnessCurve = new Curve(lux, nits); mMinimumBrightnessSpline = Spline.createSpline(lux, nits); - PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + PowerManager pm = mContext.getSystemService(PowerManager.class); mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting(); mCurrentUserId = UserHandle.USER_SYSTEM; ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces(); @@ -347,9 +348,9 @@ public final class DisplayManagerService extends SystemService { // adapter is up so that we have it's configuration. We could load it lazily, but since // we're going to have to read it in eventually we may as well do it here rather than after // we've waited for the display to register itself with us. - synchronized(mSyncRoot) { - mPersistentDataStore.loadIfNeeded(); - loadStableDisplayValuesLocked(); + synchronized (mSyncRoot) { + mPersistentDataStore.loadIfNeeded(); + loadStableDisplayValuesLocked(); } mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS); @@ -417,8 +418,10 @@ public final class DisplayManagerService extends SystemService { mOnlyCore = onlyCore; } + mDisplayModeDirector.setListener(new AllowedDisplayModeObserver()); + mDisplayModeDirector.start(); + mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS); - mHandler.sendEmptyMessage(MSG_REGISTER_BRIGHTNESS_TRACKER); } @VisibleForTesting @@ -1194,13 +1197,8 @@ public final class DisplayManagerService extends SystemService { requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate( requestedRefreshRate); } - if (display.getRequestedModeIdLocked() != requestedModeId) { - if (DEBUG) { - Slog.d(TAG, "Display " + displayId + " switching to mode " + requestedModeId); - } - display.setRequestedModeIdLocked(requestedModeId); - scheduleTraversalLocked(inTraversal); - } + mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode( + displayId, requestedModeId); } } @@ -1319,6 +1317,28 @@ public final class DisplayManagerService extends SystemService { return SurfaceControl.getDisplayedContentSample(token, maxFrames, timestamp); } + private void onAllowedDisplayModesChangedInternal() { + boolean changed = false; + synchronized (mSyncRoot) { + final int count = mLogicalDisplays.size(); + for (int i = 0; i < count; i++) { + LogicalDisplay display = mLogicalDisplays.valueAt(i); + int displayId = mLogicalDisplays.keyAt(i); + int[] allowedModes = mDisplayModeDirector.getAllowedModes(displayId); + // Note that order is important here since not all display devices are capable of + // automatically switching, so we do actually want to check for equality and not + // just equivalent contents (regardless of order). + if (!Arrays.equals(allowedModes, display.getAllowedDisplayModesLocked())) { + display.setAllowedDisplayModesLocked(allowedModes); + changed = true; + } + } + if (changed) { + scheduleTraversalLocked(false); + } + } + } + private void clearViewportsLocked() { mViewports.clear(); } @@ -1518,6 +1538,9 @@ public final class DisplayManagerService extends SystemService { display.dumpLocked(ipw); } + pw.println(); + mDisplayModeDirector.dump(pw); + final int callbackCount = mCallbacks.size(); pw.println(); pw.println("Callbacks: size=" + callbackCount); @@ -2431,4 +2454,10 @@ public final class DisplayManagerService extends SystemService { } } + + class AllowedDisplayModeObserver implements DisplayModeDirector.Listener { + public void onAllowedDisplayModesChanged() { + onAllowedDisplayModesChangedInternal(); + } + } } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java new file mode 100644 index 000000000000..af4db0730071 --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -0,0 +1,685 @@ +/* + * 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.display; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.hardware.display.DisplayManager; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Slog; +import android.util.SparseArray; +import android.view.Display; +import android.view.DisplayInfo; + +import com.android.internal.R; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Objects; + +/** + * The DisplayModeDirector is responsible for determining what modes are allowed to be + * automatically picked by the system based on system-wide and display-specific configuration. + */ +public class DisplayModeDirector { + private static final String TAG = "DisplayModeDirector"; + private static final boolean DEBUG = false; + + private static final int MSG_ALLOWED_MODES_CHANGED = 1; + + // Special ID used to indicate that given vote is to be applied globally, rather than to a + // specific display. + private static final int GLOBAL_ID = -1; + + // What we consider to be the system's "default" refresh rate. + private static final float DEFAULT_REFRESH_RATE = 60f; + + // The tolerance within which we consider something approximately equals. + private static final float EPSILON = 0.001f; + + private final Object mLock = new Object(); + private final Context mContext; + + private final DisplayModeDirectorHandler mHandler; + + // A map from the display ID to the collection of votes and their priority. The latter takes + // the form of another map from the priority to the vote itself so that each priority is + // guaranteed to have exactly one vote, which is also easily and efficiently replaceable. + private final SparseArray<SparseArray<Vote>> mVotesByDisplay; + // A map from the display ID to the supported modes on that display. + private final SparseArray<Display.Mode[]> mSupportedModesByDisplay; + // A map from the display ID to the default mode of that display. + private final SparseArray<Display.Mode> mDefaultModeByDisplay; + + private final AppRequestObserver mAppRequestObserver; + private final SettingsObserver mSettingsObserver; + private final DisplayObserver mDisplayObserver; + + + private Listener mListener; + + public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { + mContext = context; + mHandler = new DisplayModeDirectorHandler(handler.getLooper()); + mVotesByDisplay = new SparseArray<>(); + mSupportedModesByDisplay = new SparseArray<>(); + mDefaultModeByDisplay = new SparseArray<>(); + mAppRequestObserver = new AppRequestObserver(); + mSettingsObserver = new SettingsObserver(context, handler); + mDisplayObserver = new DisplayObserver(context, handler); + } + + /** + * Tells the DisplayModeDirector to update allowed votes and begin observing relevant system + * state. + * + * This has to be deferred because the object may be constructed before the rest of the system + * is ready. + */ + public void start() { + mSettingsObserver.observe(); + mDisplayObserver.observe(); + mSettingsObserver.observe(); + synchronized (mLock) { + // We may have a listener already registered before the call to start, so go ahead and + // notify them to pick up our newly initialized state. + notifyAllowedModesChangedLocked(); + } + } + + /** + * Calculates the modes the system is allowed to freely switch between based on global and + * display-specific constraints. + * + * @param displayId The display to query for. + * @return The IDs of the modes the system is allowed to freely switch between. + */ + @NonNull + public int[] getAllowedModes(int displayId) { + synchronized (mLock) { + SparseArray<Vote> votes = getVotesLocked(displayId); + Display.Mode[] modes = mSupportedModesByDisplay.get(displayId); + Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId); + if (modes == null || defaultMode == null) { + Slog.e(TAG, "Asked about unknown display, returning empty allowed set! (id=" + + displayId + ")"); + return new int[0]; + } + return getAllowedModesLocked(votes, modes, defaultMode); + } + } + + @NonNull + private SparseArray<Vote> getVotesLocked(int displayId) { + SparseArray<Vote> displayVotes = mVotesByDisplay.get(displayId); + final SparseArray<Vote> votes; + if (displayVotes != null) { + votes = displayVotes.clone(); + } else { + votes = new SparseArray<>(); + } + + SparseArray<Vote> globalVotes = mVotesByDisplay.get(GLOBAL_ID); + if (globalVotes != null) { + for (int i = 0; i < globalVotes.size(); i++) { + int priority = globalVotes.keyAt(i); + if (votes.indexOfKey(priority) < 0) { + votes.put(priority, globalVotes.valueAt(i)); + } + } + } + return votes; + } + + @NonNull + private int[] getAllowedModesLocked(@NonNull SparseArray<Vote> votes, + @NonNull Display.Mode[] modes, @NonNull Display.Mode defaultMode) { + int lowestConsideredPriority = Vote.MIN_PRIORITY; + while (lowestConsideredPriority <= Vote.MAX_PRIORITY) { + float minRefreshRate = 0f; + float maxRefreshRate = Float.POSITIVE_INFINITY; + int height = Vote.INVALID_SIZE; + int width = Vote.INVALID_SIZE; + + for (int priority = Vote.MAX_PRIORITY; + priority >= lowestConsideredPriority; + priority--) { + Vote vote = votes.get(priority); + if (vote == null) { + continue; + } + // For refresh rates, just use the tightest bounds of all the votes + minRefreshRate = Math.max(minRefreshRate, vote.minRefreshRate); + maxRefreshRate = Math.min(maxRefreshRate, vote.maxRefreshRate); + // For display size, use only the first vote we come across (i.e. the highest + // priority vote that includes the width / height). + if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE + && vote.height > 0 && vote.width > 0) { + width = vote.width; + height = vote.height; + } + } + + // If we don't have anything specifying the width / height of the display, just use the + // default width and height. We don't want these switching out from underneath us since + // it's a pretty disruptive behavior. + if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) { + width = defaultMode.getPhysicalWidth(); + height = defaultMode.getPhysicalHeight(); + } + + int[] availableModes = + filterModes(modes, width, height, minRefreshRate, maxRefreshRate); + if (availableModes.length > 0) { + if (DEBUG) { + Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes) + + " with lowest priority considered " + + Vote.priorityToString(lowestConsideredPriority) + + " and constraints: " + + "width=" + width + + ", height=" + height + + ", minRefreshRate=" + minRefreshRate + + ", maxRefreshRate=" + maxRefreshRate); + } + return availableModes; + } + + if (DEBUG) { + Slog.w(TAG, "Couldn't find available modes with lowest priority set to " + + Vote.priorityToString(lowestConsideredPriority) + + " and with the following constraints: " + + "width=" + width + + ", height=" + height + + ", minRefreshRate=" + minRefreshRate + + ", maxRefreshRate=" + maxRefreshRate); + } + // If we haven't found anything with the current set of votes, drop the current lowest + // priority vote. + lowestConsideredPriority++; + } + + // If we still haven't found anything that matches our current set of votes, just fall back + // to the default mode. + return new int[] { defaultMode.getModeId() }; + } + + private int[] filterModes(Display.Mode[] supportedModes, + int width, int height, float minRefreshRate, float maxRefreshRate) { + ArrayList<Display.Mode> availableModes = new ArrayList<>(); + for (Display.Mode mode : supportedModes) { + if (mode.getPhysicalWidth() != width || mode.getPhysicalHeight() != height) { + if (DEBUG) { + Slog.w(TAG, "Discarding mode " + mode.getModeId() + ", wrong size" + + ": desiredWidth=" + width + + ": desiredHeight=" + height + + ": actualWidth=" + mode.getPhysicalWidth() + + ": actualHeight=" + mode.getPhysicalHeight()); + } + continue; + } + final float refreshRate = mode.getRefreshRate(); + // Some refresh rates are calculated based on frame timings, so they aren't *exactly* + // equal to expected refresh rate. Given that, we apply a bit of tolerance to this + // comparison. + if (refreshRate < (minRefreshRate - EPSILON) + || refreshRate > (maxRefreshRate + EPSILON)) { + if (DEBUG) { + Slog.w(TAG, "Discarding mode " + mode.getModeId() + + ", outside refresh rate bounds" + + ": minRefreshRate=" + minRefreshRate + + ", maxRefreshRate=" + maxRefreshRate + + ", modeRefreshRate=" + refreshRate); + } + continue; + } + availableModes.add(mode); + } + final int size = availableModes.size(); + int[] availableModeIds = new int[size]; + for (int i = 0; i < size; i++) { + availableModeIds[i] = availableModes.get(i).getModeId(); + } + return availableModeIds; + } + + /** + * Gets the observer responsible for application display mode requests. + */ + @NonNull + public AppRequestObserver getAppRequestObserver() { + // We don't need to lock here because mAppRequestObserver is a final field, which is + // guaranteed to be visible on all threads after construction. + return mAppRequestObserver; + } + + /** + * Sets the listener for changes to allowed display modes. + */ + public void setListener(@Nullable Listener listener) { + synchronized (mLock) { + mListener = listener; + } + } + + /** + * Print the object's state and debug information into the given stream. + * + * @param pw The stream to dump information to. + */ + public void dump(PrintWriter pw) { + pw.println("DisplayModeDirector"); + synchronized (mLock) { + pw.println(" mSupportedModesByDisplay:"); + for (int i = 0; i < mSupportedModesByDisplay.size(); i++) { + final int id = mSupportedModesByDisplay.keyAt(i); + final Display.Mode[] modes = mSupportedModesByDisplay.valueAt(i); + pw.println(" " + id + " -> " + Arrays.toString(modes)); + } + pw.println(" mDefaultModeByDisplay:"); + for (int i = 0; i < mDefaultModeByDisplay.size(); i++) { + final int id = mDefaultModeByDisplay.keyAt(i); + final Display.Mode mode = mDefaultModeByDisplay.valueAt(i); + pw.println(" " + id + " -> " + mode); + } + pw.println(" mVotesByDisplay:"); + for (int i = 0; i < mVotesByDisplay.size(); i++) { + pw.println(" " + mVotesByDisplay.keyAt(i) + ":"); + SparseArray<Vote> votes = mVotesByDisplay.valueAt(i); + for (int p = Vote.MAX_PRIORITY; p >= Vote.MIN_PRIORITY; p--) { + Vote vote = votes.get(p); + if (vote == null) { + continue; + } + pw.println(" " + Vote.priorityToString(p) + " -> " + vote); + } + } + mSettingsObserver.dumpLocked(pw); + mAppRequestObserver.dumpLocked(pw); + } + } + + private void updateVoteLocked(int priority, Vote vote) { + updateVoteLocked(GLOBAL_ID, priority, vote); + } + + private void updateVoteLocked(int displayId, int priority, Vote vote) { + if (DEBUG) { + Slog.i(TAG, "updateVoteLocked(displayId=" + displayId + + ", priority=" + Vote.priorityToString(priority) + + ", vote=" + vote + ")"); + } + if (priority < Vote.MIN_PRIORITY || priority > Vote.MAX_PRIORITY) { + Slog.w(TAG, "Received a vote with an invalid priority, ignoring:" + + " priority=" + Vote.priorityToString(priority) + + ", vote=" + vote, new Throwable()); + return; + } + final SparseArray<Vote> votes = getOrCreateVotesByDisplay(displayId); + + Vote currentVote = votes.get(priority); + if (vote != null) { + votes.put(priority, vote); + } else { + votes.remove(priority); + } + + if (votes.size() == 0) { + if (DEBUG) { + Slog.i(TAG, "No votes left for display " + displayId + ", removing."); + } + mVotesByDisplay.remove(displayId); + } + + notifyAllowedModesChangedLocked(); + } + + private void notifyAllowedModesChangedLocked() { + if (mListener != null && !mHandler.hasMessages(MSG_ALLOWED_MODES_CHANGED)) { + // We need to post this to a handler to avoid calling out while holding the lock + // since we know there are things that both listen for changes as well as provide + // information. If we did call out while holding the lock, then there's no guaranteed + // lock order and we run the real of risk deadlock. + Message msg = mHandler.obtainMessage(MSG_ALLOWED_MODES_CHANGED, mListener); + msg.sendToTarget(); + } + } + + private SparseArray<Vote> getOrCreateVotesByDisplay(int displayId) { + int index = mVotesByDisplay.indexOfKey(displayId); + if (mVotesByDisplay.indexOfKey(displayId) >= 0) { + return mVotesByDisplay.get(displayId); + } else { + SparseArray<Vote> votes = new SparseArray<>(); + mVotesByDisplay.put(displayId, votes); + return votes; + } + } + + /** + * Listens for changes to display mode coordination. + */ + public interface Listener { + /** + * Called when the allowed display modes may have changed. + */ + void onAllowedDisplayModesChanged(); + } + + private static final class DisplayModeDirectorHandler extends Handler { + DisplayModeDirectorHandler(Looper looper) { + super(looper, null, true /*async*/); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ALLOWED_MODES_CHANGED: + Listener listener = (Listener) msg.obj; + listener.onAllowedDisplayModesChanged(); + break; + } + } + } + + private static final class Vote { + public static final int PRIORITY_USER_SETTING = 0; + // We split the app request into two priorities in case we can satisfy one desire without + // the other. + public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 1; + public static final int PRIORITY_APP_REQUEST_SIZE = 2; + public static final int PRIORITY_LOW_POWER_MODE = 3; + + // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as + // appropriate, as well as priorityToString. + + public static final int MIN_PRIORITY = PRIORITY_USER_SETTING; + public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE; + + /** + * A value signifying an invalid width or height in a vote. + */ + public static final int INVALID_SIZE = -1; + + /** + * The requested width of the display in pixels, or INVALID_SIZE; + */ + public final int width; + /** + * The requested height of the display in pixels, or INVALID_SIZE; + */ + public final int height; + + /** + * The lowest desired refresh rate. + */ + public final float minRefreshRate; + /** + * The highest desired refresh rate. + */ + public final float maxRefreshRate; + + public static Vote forRefreshRates(float minRefreshRate, float maxRefreshRate) { + return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate); + } + + public static Vote forSize(int width, int height) { + return new Vote(width, height, 0f, Float.POSITIVE_INFINITY); + } + + private Vote(int width, int height, + float minRefreshRate, float maxRefreshRate) { + this.width = width; + this.height = height; + this.minRefreshRate = minRefreshRate; + this.maxRefreshRate = maxRefreshRate; + } + + public static String priorityToString(int priority) { + switch (priority) { + case PRIORITY_USER_SETTING: + return "PRIORITY_USER_SETTING"; + case PRIORITY_APP_REQUEST_REFRESH_RATE: + return "PRIORITY_APP_REQUEST_REFRESH_RATE"; + case PRIORITY_APP_REQUEST_SIZE: + return "PRIORITY_APP_REQUEST_SIZE"; + case PRIORITY_LOW_POWER_MODE: + return "PRIORITY_LOW_POWER_MODE"; + default: + return Integer.toString(priority); + } + } + + @Override + public String toString() { + return "Vote{" + + "width=" + width + + ", height=" + height + + ", minRefreshRate=" + minRefreshRate + + ", maxRefreshRate=" + maxRefreshRate + + "}"; + } + } + + private final class SettingsObserver extends ContentObserver { + private final Uri mRefreshRateSetting = + Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); + private final Uri mLowPowerModeSetting = + Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE); + + private final Context mContext; + private final float mDefaultPeakRefreshRate; + + SettingsObserver(@NonNull Context context, @NonNull Handler handler) { + super(handler); + mContext = context; + mDefaultPeakRefreshRate = (float) context.getResources().getInteger( + R.integer.config_defaultPeakRefreshRate); + } + + public void observe() { + final ContentResolver cr = mContext.getContentResolver(); + cr.registerContentObserver(mRefreshRateSetting, false /*notifyDescendants*/, this, + UserHandle.USER_SYSTEM); + cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this, + UserHandle.USER_SYSTEM); + synchronized (mLock) { + updateRefreshRateSettingLocked(); + updateLowPowerModeSettingLocked(); + } + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + synchronized (mLock) { + if (mRefreshRateSetting.equals(uri)) { + updateRefreshRateSettingLocked(); + } else if (mLowPowerModeSetting.equals(uri)) { + updateLowPowerModeSettingLocked(); + } + } + } + + private void updateLowPowerModeSettingLocked() { + boolean inLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0; + final Vote vote; + if (inLowPowerMode) { + vote = Vote.forRefreshRates(0f, 60f); + } else { + vote = null; + } + updateVoteLocked(Vote.PRIORITY_LOW_POWER_MODE, vote); + } + + private void updateRefreshRateSettingLocked() { + float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(), + Settings.System.PEAK_REFRESH_RATE, DEFAULT_REFRESH_RATE); + Vote vote = Vote.forRefreshRates(0f, peakRefreshRate); + updateVoteLocked(Vote.PRIORITY_USER_SETTING, vote); + } + + public void dumpLocked(PrintWriter pw) { + pw.println(" SettingsObserver"); + pw.println(" mDefaultPeakRefreshRate: " + mDefaultPeakRefreshRate); + } + } + + final class AppRequestObserver { + private SparseArray<Display.Mode> mAppRequestedModeByDisplay; + + AppRequestObserver() { + mAppRequestedModeByDisplay = new SparseArray<>(); + } + + public void setAppRequestedMode(int displayId, int modeId) { + synchronized (mLock) { + setAppRequestedModeLocked(displayId, modeId); + } + } + + private void setAppRequestedModeLocked(int displayId, int modeId) { + final Display.Mode requestedMode = findModeByIdLocked(displayId, modeId); + if (Objects.equals(requestedMode, mAppRequestedModeByDisplay.get(displayId))) { + return; + } + + final Vote refreshRateVote; + final Vote sizeVote; + if (requestedMode != null) { + mAppRequestedModeByDisplay.put(displayId, requestedMode); + float refreshRate = requestedMode.getRefreshRate(); + refreshRateVote = Vote.forRefreshRates(refreshRate, refreshRate); + sizeVote = Vote.forSize(requestedMode.getPhysicalWidth(), + requestedMode.getPhysicalHeight()); + } else { + mAppRequestedModeByDisplay.remove(displayId); + refreshRateVote = null; + sizeVote = null; + } + updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote); + updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote); + return; + } + + private Display.Mode findModeByIdLocked(int displayId, int modeId) { + Display.Mode[] modes = mSupportedModesByDisplay.get(displayId); + if (modes == null) { + return null; + } + for (Display.Mode mode : modes) { + if (mode.getModeId() == modeId) { + return mode; + } + } + return null; + } + + public void dumpLocked(PrintWriter pw) { + pw.println(" AppRequestObserver"); + pw.println(" mAppRequestedModeByDisplay:"); + for (int i = 0; i < mAppRequestedModeByDisplay.size(); i++) { + final int id = mAppRequestedModeByDisplay.keyAt(i); + final Display.Mode mode = mAppRequestedModeByDisplay.valueAt(i); + pw.println(" " + id + " -> " + mode); + } + } + } + + private final class DisplayObserver implements DisplayManager.DisplayListener { + // Note that we can never call into DisplayManager or any of the non-POD classes it + // returns, while holding mLock since it may call into DMS, which might be simultaneously + // calling into us already holding its own lock. + private final Context mContext; + private final Handler mHandler; + + DisplayObserver(Context context, Handler handler) { + mContext = context; + mHandler = handler; + } + + public void observe() { + DisplayManager dm = mContext.getSystemService(DisplayManager.class); + dm.registerDisplayListener(this, mHandler); + + // Populate existing displays + SparseArray<Display.Mode[]> modes = new SparseArray<>(); + SparseArray<Display.Mode> defaultModes = new SparseArray<>(); + DisplayInfo info = new DisplayInfo(); + Display[] displays = dm.getDisplays(); + for (Display d : displays) { + final int displayId = d.getDisplayId(); + d.getDisplayInfo(info); + modes.put(displayId, info.supportedModes); + defaultModes.put(displayId, info.getDefaultMode()); + } + synchronized (mLock) { + final int size = modes.size(); + for (int i = 0; i < size; i++) { + mSupportedModesByDisplay.put(modes.keyAt(i), modes.valueAt(i)); + mDefaultModeByDisplay.put(defaultModes.keyAt(i), defaultModes.valueAt(i)); + } + } + } + + @Override + public void onDisplayAdded(int displayId) { + updateDisplayModes(displayId); + } + + @Override + public void onDisplayRemoved(int displayId) { + synchronized (mLock) { + mSupportedModesByDisplay.remove(displayId); + mDefaultModeByDisplay.remove(displayId); + } + } + + @Override + public void onDisplayChanged(int displayId) { + updateDisplayModes(displayId); + } + + private void updateDisplayModes(int displayId) { + Display d = mContext.getSystemService(DisplayManager.class).getDisplay(displayId); + DisplayInfo info = new DisplayInfo(); + d.getDisplayInfo(info); + boolean changed = false; + synchronized (mLock) { + if (!Arrays.equals(mSupportedModesByDisplay.get(displayId), info.supportedModes)) { + mSupportedModesByDisplay.put(displayId, info.supportedModes); + changed = true; + } + if (!Objects.equals(mDefaultModeByDisplay.get(displayId), info.getDefaultMode())) { + changed = true; + mDefaultModeByDisplay.put(displayId, info.getDefaultMode()); + } + if (changed) { + notifyAllowedModesChangedLocked(); + } + } + } + } +} diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 77df10bf536a..5e5ef26f6624 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -112,16 +112,18 @@ final class LocalDisplayAdapter extends DisplayAdapter { activeColorMode = Display.COLOR_MODE_INVALID; } int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken); + int[] allowedConfigs = SurfaceControl.getAllowedDisplayConfigs(displayToken); LocalDisplayDevice device = mDevices.get(physicalDisplayId); if (device == null) { // Display was added. final boolean isInternal = mDevices.size() == 0; device = new LocalDisplayDevice(displayToken, physicalDisplayId, - configs, activeConfig, colorModes, activeColorMode, isInternal); + configs, activeConfig, allowedConfigs, colorModes, activeColorMode, + isInternal); mDevices.put(physicalDisplayId, device); sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig, - colorModes, activeColorMode)) { + allowedConfigs, colorModes, activeColorMode)) { // Display properties changed. sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); } @@ -167,26 +169,30 @@ final class LocalDisplayAdapter extends DisplayAdapter { private boolean mHavePendingChanges; private int mState = Display.STATE_UNKNOWN; private int mBrightness = PowerManager.BRIGHTNESS_DEFAULT; - private int mActivePhysIndex; private int mDefaultModeId; private int mActiveModeId; private boolean mActiveModeInvalid; + private int[] mAllowedModeIds; + private boolean mAllowedModeIdsInvalid; + private int mActivePhysIndex; + private int[] mAllowedPhysIndexes; private int mActiveColorMode; private boolean mActiveColorModeInvalid; private Display.HdrCapabilities mHdrCapabilities; private boolean mSidekickActive; private SidekickInternal mSidekickInternal; - private SurfaceControl.PhysicalDisplayInfo mDisplayInfos[]; + private SurfaceControl.PhysicalDisplayInfo[] mDisplayInfos; LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo, - int[] colorModes, int activeColorMode, boolean isInternal) { + int[] allowedDisplayInfos, int[] colorModes, int activeColorMode, + boolean isInternal) { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId); mPhysicalDisplayId = physicalDisplayId; mIsInternal = isInternal; updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo, - colorModes, activeColorMode); + allowedDisplayInfos, colorModes, activeColorMode); updateColorModesLocked(colorModes, activeColorMode); mSidekickInternal = LocalServices.getService(SidekickInternal.class); if (mIsInternal) { @@ -205,9 +211,10 @@ final class LocalDisplayAdapter extends DisplayAdapter { public boolean updatePhysicalDisplayInfoLocked( SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo, - int[] colorModes, int activeColorMode) { + int[] allowedDisplayInfos, int[] colorModes, int activeColorMode) { mDisplayInfos = Arrays.copyOf(physicalDisplayInfos, physicalDisplayInfos.length); mActivePhysIndex = activeDisplayInfo; + mAllowedPhysIndexes = Arrays.copyOf(allowedDisplayInfos, allowedDisplayInfos.length); // Build an updated list of all existing modes. ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>(); boolean modesAdded = false; @@ -246,8 +253,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { break; } } - // Check whether surface flinger spontaneously changed modes out from under us. Schedule - // traversals to ensure that the correct state is reapplied if necessary. + + // Check whether surface flinger spontaneously changed modes out from under us. + // Schedule traversals to ensure that the correct state is reapplied if necessary. if (mActiveModeId != 0 && mActiveModeId != activeRecord.mMode.getModeId()) { mActiveModeInvalid = true; @@ -266,6 +274,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { for (DisplayModeRecord record : records) { mSupportedModes.put(record.mMode.getModeId(), record); } + // Update the default mode, if needed. if (findDisplayInfoIndexLocked(mDefaultModeId) < 0) { if (mDefaultModeId != 0) { @@ -274,6 +283,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { } mDefaultModeId = activeRecord.mMode.getModeId(); } + // Determine whether the active mode is still there. if (mSupportedModes.indexOfKey(mActiveModeId) < 0) { if (mActiveModeId != 0) { @@ -284,6 +294,21 @@ final class LocalDisplayAdapter extends DisplayAdapter { mActiveModeInvalid = true; } + // Determine what the currently allowed modes are + mAllowedModeIds = new int[] { mActiveModeId }; + int[] allowedModeIds = new int[mAllowedPhysIndexes.length]; + int size = 0; + for (int physIndex : mAllowedPhysIndexes) { + int modeId = findMatchingModeIdLocked(physIndex); + if (modeId > 0) { + allowedModeIds[size++] = modeId; + } + } + + // If this is different from our desired allowed modes, then mark our current set as + // invalid so we correct this on the next traversal. + mAllowedModeIdsInvalid = !Arrays.equals(allowedModeIds, mAllowedModeIds); + // Schedule traversals so that we apply pending changes. sendTraversalRequestLocked(); return true; @@ -368,11 +393,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.height = phys.height; mInfo.modeId = mActiveModeId; mInfo.defaultModeId = mDefaultModeId; - mInfo.supportedModes = new Display.Mode[mSupportedModes.size()]; - for (int i = 0; i < mSupportedModes.size(); i++) { - DisplayModeRecord record = mSupportedModes.valueAt(i); - mInfo.supportedModes[i] = record.mMode; - } + mInfo.supportedModes = getDisplayModes(mSupportedModes); mInfo.colorMode = mActiveColorMode; mInfo.supportedColorModes = new int[mSupportedColorModes.size()]; @@ -593,44 +614,104 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void requestDisplayModesLocked(int colorMode, int modeId) { - if (requestModeLocked(modeId) || - requestColorModeLocked(colorMode)) { + public void setRequestedColorModeLocked(int colorMode) { + if (requestColorModeLocked(colorMode)) { updateDeviceInfoLocked(); } } @Override + public void setAllowedDisplayModesLocked(int[] modes) { + updateAllowedModesLocked(modes); + } + + @Override public void onOverlayChangedLocked() { updateDeviceInfoLocked(); } - public boolean requestModeLocked(int modeId) { - if (modeId == 0) { - modeId = mDefaultModeId; - } else if (mSupportedModes.indexOfKey(modeId) < 0) { - Slog.w(TAG, "Requested mode " + modeId + " is not supported by this display," - + " reverting to default display mode."); - modeId = mDefaultModeId; + public void onActivePhysicalDisplayModeChangedLocked(int physIndex) { + if (updateActiveModeLocked(physIndex)) { + updateDeviceInfoLocked(); } + } - int physIndex = findDisplayInfoIndexLocked(modeId); - if (physIndex < 0) { - Slog.w(TAG, "Requested mode ID " + modeId + " not available," - + " trying with default mode ID"); - modeId = mDefaultModeId; - physIndex = findDisplayInfoIndexLocked(modeId); - } - if (mActivePhysIndex == physIndex) { + public boolean updateActiveModeLocked(int activePhysIndex) { + if (mActivePhysIndex == activePhysIndex) { return false; } - SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex); - mActivePhysIndex = physIndex; - mActiveModeId = modeId; - mActiveModeInvalid = false; + mActivePhysIndex = activePhysIndex; + mActiveModeId = findMatchingModeIdLocked(activePhysIndex); + mActiveModeInvalid = mActiveModeId == 0; + if (mActiveModeInvalid) { + Slog.w(TAG, "In unknown mode after setting allowed configs" + + ": allowedPhysIndexes=" + mAllowedPhysIndexes + + ", activePhysIndex=" + mActivePhysIndex); + } return true; } + public void updateAllowedModesLocked(int[] allowedModes) { + if (Arrays.equals(allowedModes, mAllowedModeIds) && !mAllowedModeIdsInvalid) { + return; + } + if (updateAllowedModesInternalLocked(allowedModes)) { + updateDeviceInfoLocked(); + } + } + + public boolean updateAllowedModesInternalLocked(int[] allowedModes) { + if (DEBUG) { + Slog.w(TAG, "updateAllowedModesInternalLocked(allowedModes=" + + Arrays.toString(allowedModes) + ")"); + } + int[] allowedPhysIndexes = new int[allowedModes.length]; + int size = 0; + for (int modeId : allowedModes) { + int physIndex = findDisplayInfoIndexLocked(modeId); + if (physIndex < 0) { + Slog.w(TAG, "Requested mode ID " + modeId + " not available," + + " dropping from allowed set."); + } else { + allowedPhysIndexes[size++] = physIndex; + } + } + + // If we couldn't find one or more of the suggested allowed modes then we need to + // shrink the array to its actual size. + if (size != allowedModes.length) { + allowedPhysIndexes = Arrays.copyOf(allowedPhysIndexes, size); + } + + // If we found no suitable modes, then we try again with the default mode which we + // assume has a suitable physical config. + if (size == 0) { + if (DEBUG) { + Slog.w(TAG, "No valid modes allowed, falling back to default mode (id=" + + mDefaultModeId + ")"); + } + allowedModes = new int[] { mDefaultModeId }; + allowedPhysIndexes = new int[] { findDisplayInfoIndexLocked(mDefaultModeId) }; + } + + mAllowedModeIds = allowedModes; + mAllowedModeIdsInvalid = false; + + if (Arrays.equals(mAllowedPhysIndexes, allowedPhysIndexes)) { + return false; + } + mAllowedPhysIndexes = allowedPhysIndexes; + + if (DEBUG) { + Slog.w(TAG, "Setting allowed physical configs: allowedPhysIndexes=" + + Arrays.toString(allowedPhysIndexes)); + } + + SurfaceControl.setAllowedDisplayConfigs(getDisplayTokenLocked(), allowedPhysIndexes); + int activePhysIndex = SurfaceControl.getActiveConfig(getDisplayTokenLocked()); + return updateActiveModeLocked(activePhysIndex); + } + public boolean requestColorModeLocked(int colorMode) { if (mActiveColorMode == colorMode) { return false; @@ -650,9 +731,13 @@ final class LocalDisplayAdapter extends DisplayAdapter { public void dumpLocked(PrintWriter pw) { super.dumpLocked(pw); pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId); + pw.println("mAllowedPhysIndexes=" + Arrays.toString(mAllowedPhysIndexes)); + pw.println("mAllowedModeIds=" + Arrays.toString(mAllowedModeIds)); + pw.println("mAllowedModeIdsInvalid=" + mAllowedModeIdsInvalid); pw.println("mActivePhysIndex=" + mActivePhysIndex); pw.println("mActiveModeId=" + mActiveModeId); pw.println("mActiveColorMode=" + mActiveColorMode); + pw.println("mDefaultModeId=" + mDefaultModeId); pw.println("mState=" + Display.stateToString(mState)); pw.println("mBrightness=" + mBrightness); pw.println("mBacklight=" + mBacklight); @@ -687,10 +772,31 @@ final class LocalDisplayAdapter extends DisplayAdapter { return -1; } + private int findMatchingModeIdLocked(int physIndex) { + SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[physIndex]; + for (int i = 0; i < mSupportedModes.size(); i++) { + DisplayModeRecord record = mSupportedModes.valueAt(i); + if (record.hasMatchingMode(info)) { + return record.mMode.getModeId(); + } + } + return 0; + } + private void updateDeviceInfoLocked() { mInfo = null; sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); } + + private Display.Mode[] getDisplayModes(SparseArray<DisplayModeRecord> records) { + final int size = records.size(); + Display.Mode[] modes = new Display.Mode[size]; + for (int i = 0; i < size; i++) { + DisplayModeRecord record = records.valueAt(i); + modes[i] = record.mMode; + } + return modes; + } } /** Supplies a context whose Resources apply runtime-overlays */ @@ -745,12 +851,23 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { + public void onConfigChanged(long timestampNanos, long physicalDisplayId, int physIndex) { if (DEBUG) { Slog.d(TAG, "onConfigChanged(" + "timestampNanos=" + timestampNanos - + ", builtInDisplayId=" + physicalDisplayId - + ", configId=" + configId + ")"); + + ", physicalDisplayId=" + physicalDisplayId + + ", physIndex=" + physIndex + ")"); + } + synchronized (getSyncRoot()) { + LocalDisplayDevice device = mDevices.get(physicalDisplayId); + if (device == null) { + if (DEBUG) { + Slog.d(TAG, "Received config change for unhandled physical display: " + + "physicalDisplayId=" + physicalDisplayId); + } + return; + } + device.onActivePhysicalDisplayModeChangedLocked(physIndex); } } } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index b21f0a7f0144..a7b90510e6c8 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -87,7 +87,7 @@ final class LogicalDisplay { // True if the logical display has unique content. private boolean mHasContent; - private int mRequestedModeId; + private int[] mAllowedDisplayModes = new int[0]; private int mRequestedColorMode; // The display offsets to apply to the display projection. @@ -354,12 +354,14 @@ final class LogicalDisplay { // Set the layer stack. device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack); - // Set the color mode and mode. + // Set the color mode and allowed display mode. if (device == mPrimaryDisplayDevice) { - device.requestDisplayModesLocked( - mRequestedColorMode, mRequestedModeId); + device.setAllowedDisplayModesLocked(mAllowedDisplayModes); + device.setRequestedColorModeLocked(mRequestedColorMode); } else { - device.requestDisplayModesLocked(0, 0); // Revert to default. + // Reset to default for non primary displays + device.setAllowedDisplayModesLocked(new int[] {0}); + device.setRequestedColorModeLocked(0); } // Only grab the display info now as it may have been changed based on the requests above. @@ -463,17 +465,17 @@ final class LogicalDisplay { } /** - * Requests the given mode. + * Sets the display modes the system is free to switch between. */ - public void setRequestedModeIdLocked(int modeId) { - mRequestedModeId = modeId; + public void setAllowedDisplayModesLocked(int[] modes) { + mAllowedDisplayModes = modes; } /** - * Returns the pending requested mode. + * Returns the display modes the system is free to switch between. */ - public int getRequestedModeIdLocked() { - return mRequestedModeId; + public int[] getAllowedDisplayModesLocked() { + return mAllowedDisplayModes; } /** @@ -532,7 +534,7 @@ final class LogicalDisplay { pw.println("mDisplayId=" + mDisplayId); pw.println("mLayerStack=" + mLayerStack); pw.println("mHasContent=" + mHasContent); - pw.println("mRequestedMode=" + mRequestedModeId); + pw.println("mAllowedDisplayModes=" + Arrays.toString(mAllowedDisplayModes)); pw.println("mRequestedColorMode=" + mRequestedColorMode); pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")"); pw.println("mDisplayScalingDisabled=" + mDisplayScalingDisabled); diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index 2f507d17730e..60cfbd0da2c3 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -16,9 +16,6 @@ package com.android.server.display; -import com.android.internal.util.DumpUtils; -import com.android.internal.util.IndentingPrintWriter; - import android.content.Context; import android.database.ContentObserver; import android.graphics.SurfaceTexture; @@ -32,6 +29,9 @@ import android.view.Gravity; import android.view.Surface; import android.view.SurfaceControl; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.IndentingPrintWriter; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -315,7 +315,16 @@ final class OverlayDisplayAdapter extends DisplayAdapter { } @Override - public void requestDisplayModesLocked(int color, int id) { + public void setAllowedDisplayModesLocked(int[] modes) { + final int id; + if (modes.length > 0) { + // The allowed modes should be ordered by preference, so just use the first mode + // here. + id = modes[0]; + } else { + // If we don't have any allowed modes, just use the default mode. + id = 0; + } int index = -1; if (id == 0) { // Use the default. diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 9ab99753ed00..71ec5b00608e 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -142,7 +142,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // these need to match ElapsedRealtimeFlags enum in types.hal private static final int ELAPSED_REALTIME_HAS_TIMESTAMP_NS = 1; - private static final int ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2; // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal private static final int GPS_DELETE_EPHEMERIS = 0x0001; @@ -769,18 +768,15 @@ public class GnssLocationProvider extends AbstractLocationProvider implements float bearingAccuracyDegrees = location.getBearingAccuracyDegrees(); long timestamp = location.getTime(); - int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS - | (location.hasElapsedRealtimeUncertaintyNanos() - ? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0); + int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS; long elapsedRealtimeNanos = location.getElapsedRealtimeNanos(); - long elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos(); native_inject_best_location( gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters, verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp, - elapsedRealtimeFlags, elapsedRealtimeNanos, elapsedRealtimeUncertaintyNanos); + elapsedRealtimeFlags, elapsedRealtimeNanos); } /** Returns true if the location request is too frequent. */ @@ -2174,8 +2170,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements double altitudeMeters, float speedMetersPerSec, float bearingDegrees, float horizontalAccuracyMeters, float verticalAccuracyMeters, float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees, - long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos, - long elapsedRealtimeUncertaintyNanos); + long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos); private native void native_inject_location(double latitude, double longitude, float accuracy); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 47b9c27284e5..1b14ce21bb92 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -53,6 +53,7 @@ import com.android.server.locksettings.recoverablekeystore.certificate.CertValid import com.android.server.locksettings.recoverablekeystore.certificate.CertXml; import com.android.server.locksettings.recoverablekeystore.certificate.SigXml; import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage; +import com.android.server.locksettings.recoverablekeystore.storage.CleanupManager; import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb; import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage; import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage; @@ -100,6 +101,7 @@ public class RecoverableKeyStoreManager { private final PlatformKeyManager mPlatformKeyManager; private final ApplicationKeyStorage mApplicationKeyStorage; private final TestOnlyInsecureCertificateHelper mTestCertHelper; + private final CleanupManager mCleanupManager; /** * Returns a new or existing instance. @@ -122,16 +124,24 @@ public class RecoverableKeyStoreManager { throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage()); } + RecoverySnapshotStorage snapshotStorage = + RecoverySnapshotStorage.newInstance(); + CleanupManager cleanupManager = CleanupManager.getInstance( + context.getApplicationContext(), + snapshotStorage, + db, + applicationKeyStorage); mInstance = new RecoverableKeyStoreManager( context.getApplicationContext(), db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), - RecoverySnapshotStorage.newInstance(), + snapshotStorage, new RecoverySnapshotListenersStorage(), platformKeyManager, applicationKeyStorage, - new TestOnlyInsecureCertificateHelper()); + new TestOnlyInsecureCertificateHelper(), + cleanupManager); } return mInstance; } @@ -146,7 +156,8 @@ public class RecoverableKeyStoreManager { RecoverySnapshotListenersStorage listenersStorage, PlatformKeyManager platformKeyManager, ApplicationKeyStorage applicationKeyStorage, - TestOnlyInsecureCertificateHelper TestOnlyInsecureCertificateHelper) { + TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper, + CleanupManager cleanupManager) { mContext = context; mDatabase = recoverableKeyStoreDb; mRecoverySessionStorage = recoverySessionStorage; @@ -155,8 +166,10 @@ public class RecoverableKeyStoreManager { mSnapshotStorage = snapshotStorage; mPlatformKeyManager = platformKeyManager; mApplicationKeyStorage = applicationKeyStorage; - mTestCertHelper = TestOnlyInsecureCertificateHelper; - + mTestCertHelper = testOnlyInsecureCertificateHelper; + mCleanupManager = cleanupManager; + // Clears data for removed users. + mCleanupManager.verifyKnownUsers(); try { mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase); } catch (NoSuchAlgorithmException e) { @@ -955,6 +968,9 @@ public class RecoverableKeyStoreManager { mContext.enforceCallingOrSelfPermission( Manifest.permission.RECOVER_KEYSTORE, "Caller " + Binder.getCallingUid() + " doesn't have RecoverKeyStore permission."); + int userId = UserHandle.getCallingUserId(); + int uid = Binder.getCallingUid(); + mCleanupManager.registerRecoveryAgent(userId, uid); } private boolean publicKeysMatch(PublicKey publicKey, byte[] vaultParams) { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/CleanupManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/CleanupManager.java new file mode 100644 index 000000000000..be35b50c361e --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/CleanupManager.java @@ -0,0 +1,178 @@ +/* + * 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.locksettings.recoverablekeystore.storage; + +import android.content.Context; +import android.os.ServiceSpecificException; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.locksettings.recoverablekeystore.WrappedKey; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Cleans up data when user is removed. + */ +public class CleanupManager { + private static final String TAG = "CleanupManager"; + + private final Context mContext; + private final UserManager mUserManager; + private final RecoverableKeyStoreDb mDatabase; + private final RecoverySnapshotStorage mSnapshotStorage; + private final ApplicationKeyStorage mApplicationKeyStorage; + + // Serial number can not be changed at runtime. + private Map<Integer, Long> mSerialNumbers; // Always in sync with the database. + + /** + * Creates a new instance of the class. + * IMPORTANT: {@code verifyKnownUsers} must be called before the first data access. + */ + public static CleanupManager getInstance( + Context context, + RecoverySnapshotStorage snapshotStorage, + RecoverableKeyStoreDb recoverableKeyStoreDb, + ApplicationKeyStorage applicationKeyStorage) { + return new CleanupManager( + context, + snapshotStorage, + recoverableKeyStoreDb, + UserManager.get(context), + applicationKeyStorage); + } + + @VisibleForTesting + CleanupManager( + Context context, + RecoverySnapshotStorage snapshotStorage, + RecoverableKeyStoreDb recoverableKeyStoreDb, + UserManager userManager, + ApplicationKeyStorage applicationKeyStorage) { + mContext = context; + mSnapshotStorage = snapshotStorage; + mDatabase = recoverableKeyStoreDb; + mUserManager = userManager; + mApplicationKeyStorage = applicationKeyStorage; + } + + /** + * Registers recovery agent in the system, if necessary. + */ + public synchronized void registerRecoveryAgent(int userId, int uid) { + if (mSerialNumbers == null) { + // Table was uninitialized. + verifyKnownUsers(); + } + // uid is ignored since recovery agent is a system app. + Long storedSerialNumber = mSerialNumbers.get(userId); + if (storedSerialNumber == null) { + storedSerialNumber = -1L; + } + if (storedSerialNumber != -1) { + // User was already registered. + return; + } + // User was added after {@code verifyAllUsers} call. + long currentSerialNumber = mUserManager.getSerialNumberForUser(UserHandle.of(userId)); + if (currentSerialNumber != -1) { + storeUserSerialNumber(userId, currentSerialNumber); + } + } + + /** + * Removes data if serial number for a user was changed. + */ + public synchronized void verifyKnownUsers() { + mSerialNumbers = mDatabase.getUserSerialNumbers(); + List<Integer> deletedUserIds = new ArrayList<Integer>(){}; + for (Map.Entry<Integer, Long> entry : mSerialNumbers.entrySet()) { + Integer userId = entry.getKey(); + Long storedSerialNumber = entry.getValue(); + if (storedSerialNumber == null) { + storedSerialNumber = -1L; + } + long currentSerialNumber = mUserManager.getSerialNumberForUser(UserHandle.of(userId)); + if (currentSerialNumber == -1) { + // User was removed. + deletedUserIds.add(userId); + removeDataForUser(userId); + } else if (storedSerialNumber == -1) { + // User is detected for the first time + storeUserSerialNumber(userId, currentSerialNumber); + } else if (storedSerialNumber != currentSerialNumber) { + // User has unexpected serial number - delete data related to old serial number. + deletedUserIds.add(userId); + removeDataForUser(userId); + // Register new user. + storeUserSerialNumber(userId, currentSerialNumber); + } + } + + for (Integer deletedUser : deletedUserIds) { + mSerialNumbers.remove(deletedUser); + } + } + + private void storeUserSerialNumber(int userId, long userSerialNumber) { + Log.d(TAG, "Storing serial number for user " + userId + "."); + mSerialNumbers.put(userId, userSerialNumber); + mDatabase.setUserSerialNumber(userId, userSerialNumber); + } + + /** + * Removes all data for given user, including + * + * <ul> + * <li> Recovery snapshots for all agents belonging to the {@code userId}. + * <li> Entries with data related to {@code userId} from the database. + * </ul> + */ + private void removeDataForUser(int userId) { + Log.d(TAG, "Removing data for user " + userId + "."); + List<Integer> recoveryAgents = mDatabase.getRecoveryAgents(userId); + for (Integer uid : recoveryAgents) { + mSnapshotStorage.remove(uid); + removeAllKeysForRecoveryAgent(userId, uid); + } + + mDatabase.removeUserFromAllTables(userId); + } + + /** + * Removes keys from Android KeyStore for the recovery agent; + * Doesn't remove encrypted key material from the database. + */ + private void removeAllKeysForRecoveryAgent(int userId, int uid) { + int generationId = mDatabase.getPlatformKeyGenerationId(userId); + Map<String, WrappedKey> allKeys = mDatabase.getAllKeys(userId, uid, generationId); + for (String alias : allKeys.keySet()) { + try { + // Delete KeyStore copy. + mApplicationKeyStorage.deleteEntry(userId, uid, alias); + } catch (ServiceSpecificException e) { + // Ignore errors during key removal. + Log.e(TAG, "Error while removing recoverable key " + alias + " : " + e); + } + } + } +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java index dffaffe677ad..3f5ac8e504b3 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java @@ -24,6 +24,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.security.keystore.recovery.RecoveryController; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import com.android.server.locksettings.recoverablekeystore.TestOnlyInsecureCertificateHelper; @@ -261,7 +262,7 @@ public class RecoverableKeyStoreDb { * * @hide */ - public Map<String, WrappedKey> getAllKeys(int userId, int recoveryAgentUid, + public @NonNull Map<String, WrappedKey> getAllKeys(int userId, int recoveryAgentUid, int platformKeyGenerationId) { SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase(); String[] projection = { @@ -337,6 +338,58 @@ public class RecoverableKeyStoreDb { } /** + * Returns serial numbers associated with all known users. + * -1 is used for uninitialized serial numbers. + * + * See {@code UserHandle.getSerialNumberForUser}. + * @return Map from userId to serial numbers. + */ + public @NonNull Map<Integer, Long> getUserSerialNumbers() { + SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase(); + String[] projection = { + UserMetadataEntry.COLUMN_NAME_USER_ID, + UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER}; + String selection = null; // get all rows. + String[] selectionArguments = {}; + + try ( + Cursor cursor = db.query( + UserMetadataEntry.TABLE_NAME, + projection, + selection, + selectionArguments, + /*groupBy=*/ null, + /*having=*/ null, + /*orderBy=*/ null) + ) { + Map<Integer, Long> serialNumbers = new ArrayMap<>(); + while (cursor.moveToNext()) { + int userId = cursor.getInt( + cursor.getColumnIndexOrThrow(UserMetadataEntry.COLUMN_NAME_USER_ID)); + long serialNumber = cursor.getLong(cursor.getColumnIndexOrThrow( + UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER)); + serialNumbers.put(userId, serialNumber); + } + return serialNumbers; + } + } + + /** + * Sets the {@code serialNumber} for the user {@code userId}. + * + * @return The primary key of the inserted row, or -1 if failed. + */ + public long setUserSerialNumber(int userId, long serialNumber) { + SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); + ContentValues values = new ContentValues(); + values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, userId); + values.put(UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER, serialNumber); + long result = db.replace( + UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values); + return result; + } + + /** * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}. */ public void invalidateKeysWithOldGenerationId(int userId, int newGenerationId) { @@ -424,8 +477,7 @@ public class RecoverableKeyStoreDb { */ @Nullable public Long getRecoveryServiceCertSerial(int userId, int uid, @NonNull String rootAlias) { - return getLong(userId, uid, rootAlias, - RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL); + return getLong(userId, uid, rootAlias, RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL); } /** @@ -441,7 +493,7 @@ public class RecoverableKeyStoreDb { */ public long setRecoveryServiceCertSerial(int userId, int uid, @NonNull String rootAlias, long serial) { - return setLong(userId, uid, rootAlias, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, + return setLong(userId, uid, rootAlias, RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL, serial); } @@ -457,8 +509,7 @@ public class RecoverableKeyStoreDb { */ @Nullable public CertPath getRecoveryServiceCertPath(int userId, int uid, @NonNull String rootAlias) { - byte[] bytes = getBytes(userId, uid, rootAlias, - RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH); + byte[] bytes = getBytes(userId, uid, rootAlias, RootOfTrustEntry.COLUMN_NAME_CERT_PATH); if (bytes == null) { return null; } @@ -489,7 +540,7 @@ public class RecoverableKeyStoreDb { if (certPath.getCertificates().size() == 0) { throw new CertificateEncodingException("No certificate contained in the cert path."); } - return setBytes(userId, uid, rootAlias, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, + return setBytes(userId, uid, rootAlias, RootOfTrustEntry.COLUMN_NAME_CERT_PATH, certPath.getEncoded(CERT_PATH_ENCODING)); } @@ -1189,6 +1240,63 @@ public class RecoverableKeyStoreDb { RootOfTrustEntry.TABLE_NAME, values, selection, selectionArguments); } + /** + * Removes all entries for given {@code userId}. + */ + public void removeUserFromAllTables(int userId) { + removeUserFromKeysTable(userId); + removeUserFromUserMetadataTable(userId); + removeUserFromRecoveryServiceMetadataTable(userId); + removeUserFromRootOfTrustTable(userId); + } + + /** + * Removes all entries for given userId from Keys table. + * + * @return {@code true} if deleted a row. + */ + private boolean removeUserFromKeysTable(int userId) { + SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); + String selection = KeysEntry.COLUMN_NAME_USER_ID + " = ?"; + String[] selectionArgs = {Integer.toString(userId)}; + return db.delete(KeysEntry.TABLE_NAME, selection, selectionArgs) > 0; + } + + /** + * Removes all entries for given userId from UserMetadata table. + * + * @return {@code true} if deleted a row. + */ + private boolean removeUserFromUserMetadataTable(int userId) { + SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); + String selection = UserMetadataEntry.COLUMN_NAME_USER_ID + " = ?"; + String[] selectionArgs = {Integer.toString(userId)}; + return db.delete(UserMetadataEntry.TABLE_NAME, selection, selectionArgs) > 0; + } + + /** + * Removes all entries for given userId from RecoveryServiceMetadata table. + * + * @return {@code true} if deleted a row. + */ + private boolean removeUserFromRecoveryServiceMetadataTable(int userId) { + SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); + String selection = RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ?"; + String[] selectionArgs = {Integer.toString(userId)}; + return db.delete(RecoveryServiceMetadataEntry.TABLE_NAME, selection, selectionArgs) > 0; + } + + /** + * Removes all entries for given userId from RootOfTrust table. + * + * @return {@code true} if deleted a row. + */ + private boolean removeUserFromRootOfTrustTable(int userId) { + SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); + String selection = RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ?"; + String[] selectionArgs = {Integer.toString(userId)}; + return db.delete(RootOfTrustEntry.TABLE_NAME, selection, selectionArgs) > 0; + } /** * Creates an empty row in the recovery service metadata table if such a row doesn't exist for diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java index b58ee4bc9d74..e79d11732dd9 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java @@ -20,6 +20,8 @@ import android.provider.BaseColumns; /** * Contract for recoverable key database. Describes the tables present. + * + * Make sure that {@code removeUserFromAllKnownTables} is updated, when new table is added. */ class RecoverableKeyStoreDbContract { /** @@ -91,6 +93,11 @@ class RecoverableKeyStoreDbContract { * is used to wrap recoverable keys on disk. */ static final String COLUMN_NAME_PLATFORM_KEY_GENERATION_ID = "platform_key_generation_id"; + + /** + * Serial number for the user which can not be reused. Default value is {@code -1}. + */ + static final String COLUMN_NAME_USER_SERIAL_NUMBER = "user_serial_number"; } /** diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java index b0613da35d28..cd5e8cf65a2d 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java @@ -32,7 +32,7 @@ import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKe class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper { private static final String TAG = "RecoverableKeyStoreDbHp"; - static final int DATABASE_VERSION = 5; + static final int DATABASE_VERSION = 6; // Added user id serial number. private static final String DATABASE_NAME = "recoverablekeystore.db"; private static final String SQL_CREATE_KEYS_ENTRY = @@ -54,7 +54,8 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper { "CREATE TABLE " + UserMetadataEntry.TABLE_NAME + "( " + UserMetadataEntry._ID + " INTEGER PRIMARY KEY," + UserMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER UNIQUE," - + UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER)"; + + UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER," + + UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER + " INTEGER DEFAULT -1)"; private static final String SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY = "CREATE TABLE " + RecoveryServiceMetadataEntry.TABLE_NAME + " (" @@ -141,6 +142,11 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper { oldVersion = 5; } + if (oldVersion < 6 && newVersion >= 6) { + upgradeDbForVersion6(db); + oldVersion = 6; + } + if (oldVersion != newVersion) { Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version"); } @@ -179,6 +185,15 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper { KeysEntry.COLUMN_NAME_KEY_METADATA, "BLOB", /*defaultStr=*/ null); } + private void upgradeDbForVersion6(SQLiteDatabase db) { + Log.d(TAG, "Updating recoverable keystore database to version 6"); + // adds a column to store the user serial number + addColumnToTable(db, UserMetadataEntry.TABLE_NAME, + UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER, + "INTEGER DEFAULT -1", + /*defaultStr=*/ null); + } + private static void addColumnToTable( SQLiteDatabase db, String tableName, String column, String columnType, String defaultStr) { diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 9e9128430e01..05af13ab9eec 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -744,12 +744,8 @@ public class LauncherAppsService extends SystemService { if (!canAccessProfile(user.getIdentifier(), "Cannot access usage limit")) { return null; } - - final PackageManagerInternal pmi = - LocalServices.getService(PackageManagerInternal.class); - final ComponentName cn = pmi.getDefaultHomeActivity(user.getIdentifier()); - if (!cn.getPackageName().equals(callingPackage)) { - throw new SecurityException("Caller is not the active launcher"); + if (!mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) { + throw new SecurityException("Caller is not the recents app"); } final UsageStatsManagerInternal.AppUsageLimitData data = diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index b72e83692e8a..a3b72fd02654 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -481,6 +481,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + if (callingUid == Process.SYSTEM_UID) { + params.installFlags |= PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE; + } else { + params.installFlags &= ~PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE; + } + boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0; if (params.isStaged || isApex) { mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG); diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 3218c8608d77..ff81ad56f45f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -806,7 +806,7 @@ public class PackageManagerServiceUtils { */ public static boolean isDowngradePermitted(int installFlags, int applicationFlags) { // If installed, the package will get access to data left on the device by its - // predecessor. As a security measure, this is permited only if this is not a + // predecessor. As a security measure, this is permitted only if this is not a // version downgrade or if the predecessor package is marked as debuggable and // a downgrade is explicitly requested. // @@ -818,12 +818,21 @@ public class PackageManagerServiceUtils { // installFlags. This is because we aim to keep the behavior of debuggable // platform builds as close as possible to the behavior of non-debuggable // platform builds. + // + // In case of user builds, downgrade is permitted only for the system server initiated + // sessions. This is enforced by INSTALL_RESPECT_ALLOW_DOWNGRADE flag parameter. final boolean downgradeRequested = (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0; - final boolean packageDebuggable = - (applicationFlags - & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - return (downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable)); + if (!downgradeRequested) { + return false; + } + final boolean isDebuggable = + Build.IS_DEBUGGABLE || ((applicationFlags + & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + if (isDebuggable) { + return true; + } + return (installFlags & PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE) != 0; } /** diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index f52f3a3627ad..e241ba63f082 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -599,6 +599,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } } } + + mPackageHealthObserver.onBootCompleted(); }); } diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index d24f21781b39..d8f07feb1ddb 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -26,6 +26,8 @@ import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; +import android.os.Environment; +import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.PowerManager; @@ -39,6 +41,12 @@ import com.android.server.PackageWatchdog; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; +import libcore.io.IoUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; import java.util.Collections; import java.util.List; @@ -50,14 +58,19 @@ import java.util.List; public final class RollbackPackageHealthObserver implements PackageHealthObserver { private static final String TAG = "RollbackPackageHealthObserver"; private static final String NAME = "rollback-observer"; - private Context mContext; - private Handler mHandler; + private static final int INVALID_ROLLBACK_ID = -1; + private final Context mContext; + private final Handler mHandler; + private final File mLastStagedRollbackIdFile; RollbackPackageHealthObserver(Context context) { mContext = context; HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver"); handlerThread.start(); mHandler = handlerThread.getThreadHandler(); + File dataDir = new File(Environment.getDataDirectory(), "rollback-observer"); + dataDir.mkdirs(); + mLastStagedRollbackIdFile = new File(dataDir, "last-staged-rollback-id"); PackageWatchdog.getInstance(mContext).registerHealthObserver(this); } @@ -112,15 +125,19 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, RollbackManager.STATUS_FAILURE); if (status == RollbackManager.STATUS_SUCCESS) { - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); if (rollback.isStaged()) { int rollbackId = rollback.getRollbackId(); BroadcastReceiver listener = - listenForStagedSessionReady(rollbackManager, rollbackId); - handleStagedSessionChange(rollbackManager, rollbackId, listener); + listenForStagedSessionReady(rollbackManager, rollbackId, + moduleMetadataPackage); + handleStagedSessionChange(rollbackManager, rollbackId, listener, + moduleMetadataPackage); + } else { + StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, + StatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + moduleMetadataPackage.getPackageName(), + moduleMetadataPackage.getVersionCode()); } } else { StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, @@ -152,6 +169,71 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs); } + /** Verifies the rollback state after a reboot. */ + public void onBootCompleted() { + int rollbackId = popLastStagedRollbackId(); + if (rollbackId == INVALID_ROLLBACK_ID) { + // No staged rollback before reboot + return; + } + + RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); + PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); + RollbackInfo rollback = null; + for (RollbackInfo info : rollbackManager.getRecentlyCommittedRollbacks()) { + if (rollbackId == info.getRollbackId()) { + rollback = info; + break; + } + } + + if (rollback == null) { + Slog.e(TAG, "rollback info not found for last staged rollback: " + rollbackId); + return; + } + + String moduleMetadataPackageName = getModuleMetadataPackageName(); + if (moduleMetadataPackageName == null) { + // Only log mainline staged rollbacks + return; + } + + // Use the version of the metadata package that was installed before + // we rolled back for logging purposes. + VersionedPackage moduleMetadataPackage = null; + for (PackageRollbackInfo packageRollback : rollback.getPackages()) { + if (moduleMetadataPackageName.equals(packageRollback.getPackageName())) { + moduleMetadataPackage = packageRollback.getVersionRolledBackFrom(); + break; + } + } + + if (moduleMetadataPackage == null) { + // Only log mainline staged rollbacks + return; + } + + int sessionId = rollback.getCommittedSessionId(); + PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId); + if (sessionInfo == null) { + Slog.e(TAG, "On boot completed, could not load session id " + sessionId); + return; + } + if (sessionInfo.isStagedSessionApplied()) { + StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + moduleMetadataPackage.getPackageName(), + moduleMetadataPackage.getVersionCode()); + } else if (sessionInfo.isStagedSessionReady()) { + // TODO: What do for staged session ready but not applied + } else { + StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + moduleMetadataPackage.getPackageName(), + moduleMetadataPackage.getVersionCode()); + } + } + private Pair<RollbackInfo, Boolean> getAvailableRollback(RollbackManager rollbackManager, VersionedPackage failedPackage, VersionedPackage moduleMetadataPackage) { for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) { @@ -174,12 +256,20 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve return null; } - private VersionedPackage getModuleMetadataPackage() { + private String getModuleMetadataPackageName() { String packageName = mContext.getResources().getString( R.string.config_defaultModuleMetadataProvider); if (TextUtils.isEmpty(packageName)) { return null; } + return packageName; + } + + private VersionedPackage getModuleMetadataPackage() { + String packageName = getModuleMetadataPackageName(); + if (packageName == null) { + return null; + } try { return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo( @@ -191,12 +281,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager, - int rollbackId) { + int rollbackId, VersionedPackage moduleMetadataPackage) { BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { handleStagedSessionChange(rollbackManager, - rollbackId, this /* BroadcastReceiver */); + rollbackId, this /* BroadcastReceiver */, moduleMetadataPackage); } }; IntentFilter sessionUpdatedFilter = @@ -206,7 +296,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId, - BroadcastReceiver listener) { + BroadcastReceiver listener, VersionedPackage moduleMetadataPackage) { PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); List<RollbackInfo> recentRollbacks = @@ -220,11 +310,52 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve packageInstaller.getSessionInfo(sessionId); if (sessionInfo.isStagedSessionReady()) { mContext.unregisterReceiver(listener); + saveLastStagedRollbackId(rollbackId); + StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, + StatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, + moduleMetadataPackage.getPackageName(), + moduleMetadataPackage.getVersionCode()); mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); } else if (sessionInfo.isStagedSessionFailed()) { + StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, + StatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + moduleMetadataPackage.getPackageName(), + moduleMetadataPackage.getVersionCode()); mContext.unregisterReceiver(listener); } } } } + + private void saveLastStagedRollbackId(int stagedRollbackId) { + try { + FileOutputStream fos = new FileOutputStream(mLastStagedRollbackIdFile); + PrintWriter pw = new PrintWriter(fos); + pw.println(stagedRollbackId); + pw.flush(); + FileUtils.sync(fos); + pw.close(); + } catch (IOException e) { + Slog.e(TAG, "Failed to save last staged rollback id", e); + mLastStagedRollbackIdFile.delete(); + } + } + + private int popLastStagedRollbackId() { + int rollbackId = INVALID_ROLLBACK_ID; + if (!mLastStagedRollbackIdFile.exists()) { + return rollbackId; + } + + try { + rollbackId = Integer.parseInt( + IoUtils.readFileAsString(mLastStagedRollbackIdFile.getAbsolutePath()).trim()); + } catch (IOException | NumberFormatException e) { + Slog.e(TAG, "Failed to retrieve last staged rollback id", e); + } + mLastStagedRollbackIdFile.delete(); + return rollbackId; + } } diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index ef771406805b..a5d291f94751 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -27,12 +27,8 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; -import android.service.textclassifier.IConversationActionsCallback; -import android.service.textclassifier.ITextClassificationCallback; +import android.service.textclassifier.ITextClassifierCallback; import android.service.textclassifier.ITextClassifierService; -import android.service.textclassifier.ITextLanguageCallback; -import android.service.textclassifier.ITextLinksCallback; -import android.service.textclassifier.ITextSelectionCallback; import android.service.textclassifier.TextClassifierService; import android.util.Slog; import android.util.SparseArray; @@ -132,7 +128,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi @Override public void onSuggestSelection( TextClassificationSessionId sessionId, - TextSelection.Request request, ITextSelectionCallback callback) + TextSelection.Request request, ITextClassifierCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); @@ -155,7 +151,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi @Override public void onClassifyText( TextClassificationSessionId sessionId, - TextClassification.Request request, ITextClassificationCallback callback) + TextClassification.Request request, ITextClassifierCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); @@ -178,7 +174,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi @Override public void onGenerateLinks( TextClassificationSessionId sessionId, - TextLinks.Request request, ITextLinksCallback callback) + TextLinks.Request request, ITextClassifierCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); @@ -241,7 +237,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi public void onDetectLanguage( TextClassificationSessionId sessionId, TextLanguage.Request request, - ITextLanguageCallback callback) throws RemoteException { + ITextClassifierCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); validateInput(mContext, request.getCallingPackageName()); @@ -264,7 +260,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi public void onSuggestConversationActions( TextClassificationSessionId sessionId, ConversationActions.Request request, - IConversationActionsCallback callback) throws RemoteException { + ITextClassifierCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); validateInput(mContext, request.getCallingPackageName()); diff --git a/services/core/java/com/android/server/utils/FlagNamespaceUtils.java b/services/core/java/com/android/server/utils/FlagNamespaceUtils.java index f26121eac939..f8c7447fc55d 100644 --- a/services/core/java/com/android/server/utils/FlagNamespaceUtils.java +++ b/services/core/java/com/android/server/utils/FlagNamespaceUtils.java @@ -19,6 +19,7 @@ package com.android.server.utils; import android.annotation.Nullable; import android.provider.DeviceConfig; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.RescueParty; import java.util.ArrayList; @@ -41,20 +42,23 @@ public final class FlagNamespaceUtils { /** * Name of the special namespace in DeviceConfig table used for communicating resets. */ - private static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace"; + @VisibleForTesting + public static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace"; /** * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the * first time flags are written to the new namespace in the {@link DeviceConfig}. */ - private static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces"; + @VisibleForTesting + public static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces"; /** * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given * namespace flags are reset. */ - private static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package"; + @VisibleForTesting + public static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package"; private static final String DELIMITER = ":"; /** * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG} @@ -97,11 +101,25 @@ public final class FlagNamespaceUtils { * Reset all namespaces in DeviceConfig with consumed resetMode. */ public static void resetDeviceConfig(int resetMode) { - List<String> allKnownNamespaces = getAllKnownDeviceConfigNamespacesList(); - for (String namespace : allKnownNamespaces) { + resetDeviceConfig(resetMode, getAllKnownDeviceConfigNamespacesList()); + } + + /** + * Reset all consumed namespaces in DeviceConfig with consumed resetMode. + */ + public static void resetDeviceConfig(int resetMode, List<String> namespacesList) { + for (String namespace : namespacesList) { DeviceConfig.resetToDefaults(resetMode, namespace); } - addToKnownResetNamespaces(allKnownNamespaces); + addToKnownResetNamespaces(namespacesList); + } + + /** + * Resets known reset namespaces flag counter for tests only. + */ + @VisibleForTesting + public static void resetKnownResetNamespacesFlagCounterForTest() { + sKnownResetNamespacesFlagCounter = -1; } /** diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index bb1e00113174..e53fde96e844 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -474,7 +474,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub int wallpaperId; if (wallpaper.equals(mFallbackWallpaper)) { - extractDefaultImageWallpaperColors(); + synchronized (mLock) { + if (mFallbackWallpaper.primaryColors != null) return; + } + final WallpaperColors colors = extractDefaultImageWallpaperColors(); + synchronized (mLock) { + mFallbackWallpaper.primaryColors = colors; + } return; } @@ -499,23 +505,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } else if (defaultImageWallpaper) { // There is no crop and source file because this is default image wallpaper. - try (final InputStream is = - WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) { - if (is != null) { - try { - final BitmapFactory.Options options = new BitmapFactory.Options(); - final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); - if (bitmap != null) { - colors = WallpaperColors.fromBitmap(bitmap); - bitmap.recycle(); - } - } catch (OutOfMemoryError e) { - Slog.w(TAG, "Can't decode default wallpaper stream", e); - } - } - } catch (IOException e) { - Slog.w(TAG, "Can't close default wallpaper stream", e); - } + colors = extractDefaultImageWallpaperColors(); } if (colors == null) { @@ -535,37 +525,41 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private void extractDefaultImageWallpaperColors() { + private WallpaperColors extractDefaultImageWallpaperColors() { + if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors"); + synchronized (mLock) { - if (mFallbackWallpaper.primaryColors != null) return; + if (mCacheDefaultImageWallpaperColors != null) return mCacheDefaultImageWallpaperColors; } - if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors"); WallpaperColors colors = null; - final InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM); - if (is != null) { - try { - final BitmapFactory.Options options = new BitmapFactory.Options(); - final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); - if (bitmap != null) { - colors = WallpaperColors.fromBitmap(bitmap); - bitmap.recycle(); - } - } catch (OutOfMemoryError e) { - Slog.w(TAG, "Can't decode default wallpaper stream", e); - } finally { - IoUtils.closeQuietly(is); + try (InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) { + if (is == null) { + Slog.w(TAG, "Can't open default wallpaper stream"); + return null; } + + final BitmapFactory.Options options = new BitmapFactory.Options(); + final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); + if (bitmap != null) { + colors = WallpaperColors.fromBitmap(bitmap); + bitmap.recycle(); + } + } catch (OutOfMemoryError e) { + Slog.w(TAG, "Can't decode default wallpaper stream", e); + } catch (IOException e) { + Slog.w(TAG, "Can't close default wallpaper stream", e); } if (colors == null) { Slog.e(TAG, "Extract default image wallpaper colors failed"); - return; + } else { + synchronized (mLock) { + mCacheDefaultImageWallpaperColors = colors; + } } - synchronized (mLock) { - mFallbackWallpaper.primaryColors = colors; - } + return colors; } /** @@ -815,6 +809,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private final ComponentName mImageWallpaper; /** + * Default image wallpaper shall never changed after system service started, caching it when we + * first read the image file. + */ + private WallpaperColors mCacheDefaultImageWallpaperColors; + + /** * Name of the default wallpaper component; might be different from mImageWallpaper */ private final ComponentName mDefaultWallpaperComponent; diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 9f04166ea4c0..23bed7b4d4b8 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1009,6 +1009,12 @@ class ActivityStarter { if (mService.isDeviceOwner(callingPackage)) { return false; } + // don't abort if the callingPackage is temporarily whitelisted + if (mService.isPackageNameWhitelistedForBgActivityStarts(callingPackage)) { + Slog.w(TAG, "Background activity start for " + callingPackage + + " temporarily whitelisted. This will not be supported in future Q builds."); + return false; + } // anything that has fallen through would currently be aborted Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage + "; callingUid: " + callingUid diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index d747198bc3f1..3255bc6f43b9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5210,6 +5210,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mAmInternal.isBackgroundActivityStartsEnabled(); } + boolean isPackageNameWhitelistedForBgActivityStarts(String packageName) { + return mAmInternal.isPackageNameWhitelistedForBgActivityStarts(packageName); + } + void enableScreenAfterBoot(boolean booted) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN, SystemClock.uptimeMillis()); diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index e8882ec12244..d39f20c0f214 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -491,10 +491,6 @@ static jobject translateGnssLocation(JNIEnv* env, SET(ElapsedRealtimeNanos, location.elapsedRealtime.timestampNs); } - if (flags & ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS) { - SET(ElapsedUncertaintyRealtimeNanos, location.elapsedRealtime.timeUncertaintyNs); - } - return object.get(); } @@ -525,8 +521,7 @@ static GnssLocation_V2_0 createGnssLocation_V2_0( jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees, jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters, jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, - jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos, - jlong elapsedRealtimeUncertaintyNanos) { + jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos) { GnssLocation_V2_0 location; location.v1_0 = createGnssLocation_V1_0( gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters, @@ -536,7 +531,6 @@ static GnssLocation_V2_0 createGnssLocation_V2_0( location.elapsedRealtime.flags = static_cast<uint16_t>(elapsedRealtimeFlags); location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos); - location.elapsedRealtime.timeUncertaintyNs = static_cast<uint64_t>(elapsedRealtimeUncertaintyNanos); return location; } @@ -1893,8 +1887,7 @@ static void android_location_GnssLocationProvider_inject_best_location( jfloat bearingAccuracyDegrees, jlong timestamp, jint elapsedRealtimeFlags, - jlong elapsedRealtimeNanos, - jlong elapsedRealtimeUncertaintyNanos) { + jlong elapsedRealtimeNanos) { if (gnssHal_V2_0 != nullptr) { GnssLocation_V2_0 location = createGnssLocation_V2_0( gnssLocationFlags, @@ -1909,8 +1902,7 @@ static void android_location_GnssLocationProvider_inject_best_location( bearingAccuracyDegrees, timestamp, elapsedRealtimeFlags, - elapsedRealtimeNanos, - elapsedRealtimeUncertaintyNanos); + elapsedRealtimeNanos); auto result = gnssHal_V2_0->injectBestLocation_2_0(location); if (!result.isOk() || !result) { @@ -2821,7 +2813,7 @@ static const JNINativeMethod sMethods[] = { android_location_GnssLocationProvider_read_nmea)}, {"native_inject_time", "(JJI)V", reinterpret_cast<void *>( android_location_GnssLocationProvider_inject_time)}, - {"native_inject_best_location", "(IDDDFFFFFFJIJJ)V", reinterpret_cast<void *>( + {"native_inject_best_location", "(IDDDFFFFFFJIJ)V", reinterpret_cast<void *>( android_location_GnssLocationProvider_inject_best_location)}, {"native_inject_location", "(DDF)V", reinterpret_cast<void *>( android_location_GnssLocationProvider_inject_location)}, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f496e817bc6c..36251f52d985 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -172,7 +172,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; -import android.os.ParcelableException; import android.os.PersistableBundle; import android.os.PowerManager; import android.os.PowerManagerInternal; @@ -5338,9 +5337,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { */ @Override public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) { - if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) { + if (!mHasFeature) { return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS; } + if (!mLockPatternUtils.hasSecureLockScreen()) { + // No strong auth timeout on devices not supporting the + // {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature + return 0; + } enforceFullCrossUsersPermission(userId); synchronized (getLockObject()) { if (who != null) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a19d5d5a5d76..eba0081291ca 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1881,19 +1881,6 @@ public final class SystemServer { mSystemServiceManager.startService(IncidentCompanionService.class); traceEnd(); - if (safeMode) { - traceBeginAndSlog("EnterSafeModeAndDisableJitCompilation"); - mActivityManagerService.enterSafeMode(); - // Disable the JIT for the system_server process - VMRuntime.getRuntime().disableJitCompilation(); - traceEnd(); - } else { - // Enable the JIT for the system_server process - traceBeginAndSlog("StartJitCompilation"); - VMRuntime.getRuntime().startJitCompilation(); - traceEnd(); - } - // MMS service broker traceBeginAndSlog("StartMmsService"); mmsService = mSystemServiceManager.startService(MmsServiceBroker.class); diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java index b13735cbf3b7..36825af527b1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java @@ -35,9 +35,12 @@ import android.content.Context; import android.os.RecoverySystem; import android.os.SystemProperties; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.provider.Settings; import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.server.am.SettingsToPropertiesMapper; +import com.android.server.utils.FlagNamespaceUtils; import org.junit.After; import org.junit.Before; @@ -56,6 +59,10 @@ import java.util.HashMap; public class RescuePartyTest { private static final int PERSISTENT_APP_UID = 12; private static final long CURRENT_NETWORK_TIME_MILLIS = 0L; + private static final String FAKE_NATIVE_NAMESPACE1 = "native1"; + private static final String FAKE_NATIVE_NAMESPACE2 = "native2"; + private static final String[] FAKE_RESET_NATIVE_NAMESPACES = + {FAKE_NATIVE_NAMESPACE1, FAKE_NATIVE_NAMESPACE2}; private MockitoSession mSession; @@ -73,9 +80,11 @@ public class RescuePartyTest { ExtendedMockito.mockitoSession().initMocks( this) .strictness(Strictness.LENIENT) + .spyStatic(DeviceConfig.class) .spyStatic(SystemProperties.class) .spyStatic(Settings.Global.class) .spyStatic(Settings.Secure.class) + .spyStatic(SettingsToPropertiesMapper.class) .spyStatic(RecoverySystem.class) .spyStatic(RescueParty.class) .startMocking(); @@ -121,8 +130,17 @@ public class RescuePartyTest { } ).when(() -> SystemProperties.getLong(anyString(), anyLong())); + // Mock DeviceConfig + doAnswer((Answer<Boolean>) invocationOnMock -> true) + .when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(), + anyBoolean())); + doAnswer((Answer<Void>) invocationOnMock -> null) + .when(() -> DeviceConfig.resetToDefaults(anyInt(), anyString())); + + doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime()); RescueParty.resetAllThresholds(); + FlagNamespaceUtils.resetKnownResetNamespacesFlagCounterForTest(); SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(RescueParty.LEVEL_NONE)); @@ -278,10 +296,32 @@ public class RescuePartyTest { SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE)); } + @Test + public void testNativeRescuePartyResets() { + doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed()); + doReturn(FAKE_RESET_NATIVE_NAMESPACES).when( + () -> SettingsToPropertiesMapper.getResetNativeCategories()); + + RescueParty.onSettingsProviderPublished(mMockContext); + + verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS, + FAKE_NATIVE_NAMESPACE1)); + verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS, + FAKE_NATIVE_NAMESPACE2)); + + ExtendedMockito.verify( + () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY, + FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 0, + FAKE_NATIVE_NAMESPACE1, /*makeDefault=*/true)); + ExtendedMockito.verify( + () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY, + FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 1, + FAKE_NATIVE_NAMESPACE2, /*makeDefault=*/true)); + } + private void verifySettingsResets(int resetMode) { verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null, - resetMode, - UserHandle.USER_SYSTEM)); + resetMode, UserHandle.USER_SYSTEM)); verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(), eq(resetMode), anyInt())); } diff --git a/services/tests/runtests.py b/services/tests/runtests.py index f19cc5d567ec..4c8b4bad8019 100755 --- a/services/tests/runtests.py +++ b/services/tests/runtests.py @@ -19,7 +19,7 @@ import subprocess import sys INSTRUMENTED_PACKAGE_RUNNER = ('com.android.frameworks.servicestests/' - 'android.support.test.runner.AndroidJUnitRunner') + 'androidx.test.runner.AndroidJUnitRunner') PACKAGE_WHITELIST = ( "com.android.server", diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index c78b96d2d294..5bab65c8b642 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage; +import com.android.server.locksettings.recoverablekeystore.storage.CleanupManager; import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb; import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage; import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage; @@ -154,6 +155,7 @@ public class RecoverableKeyStoreManagerTest { @Mock private KeyguardManager mKeyguardManager; @Mock private PlatformKeyManager mPlatformKeyManager; @Mock private ApplicationKeyStorage mApplicationKeyStorage; + @Mock private CleanupManager mCleanupManager; @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper; private RecoverableKeyStoreDb mRecoverableKeyStoreDb; @@ -191,7 +193,8 @@ public class RecoverableKeyStoreManagerTest { mMockListenersStorage, mPlatformKeyManager, mApplicationKeyStorage, - mTestOnlyInsecureCertificateHelper); + mTestOnlyInsecureCertificateHelper, + mCleanupManager); } @After diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/CleanupManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/CleanupManagerTest.java new file mode 100644 index 000000000000..0b15a126e98a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/CleanupManagerTest.java @@ -0,0 +1,116 @@ +/* + * 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.locksettings.recoverablekeystore.storage; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.UserHandle; +import android.os.UserManager; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class CleanupManagerTest { + private static final int USER_ID = 10; + private static final int USER_ID_2 = 20; + private static final int UID = 1234; + private static final long USER_SERIAL_NUMBER = 101L; + private static final long USER_SERIAL_NUMBER_2 = 202L; + + private Context mContext; + private CleanupManager mManager; + + @Mock private RecoverableKeyStoreDb mDatabase; + @Mock private RecoverySnapshotStorage mRecoverySnapshotStorage; + @Mock private UserManager mUserManager; + @Mock private ApplicationKeyStorage mApplicationKeyStorage; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mContext = InstrumentationRegistry.getTargetContext(); + mManager = new CleanupManager(mContext, mRecoverySnapshotStorage, mDatabase, mUserManager, + mApplicationKeyStorage); + } + + @Test + public void registerRecoveryAgent_unknownUser_storesInDb() throws Exception { + when(mDatabase.getUserSerialNumbers()).thenReturn(new HashMap<>()); + when(mUserManager.getSerialNumberForUser(eq(UserHandle.of(USER_ID)))) + .thenReturn(USER_SERIAL_NUMBER); + when(mUserManager.getSerialNumberForUser(eq(UserHandle.of(USER_ID_2)))) + .thenReturn(USER_SERIAL_NUMBER_2); + + mManager.registerRecoveryAgent(USER_ID, UID); + mManager.registerRecoveryAgent(USER_ID_2, UID); + + verify(mDatabase).setUserSerialNumber(USER_ID, USER_SERIAL_NUMBER); + verify(mDatabase).setUserSerialNumber(USER_ID_2, USER_SERIAL_NUMBER_2); + + } + + @Test + public void registerRecoveryAgent_registersSameUser_doesntChangeDb() throws Exception { + when(mDatabase.getUserSerialNumbers()).thenReturn(new HashMap<>()); + when(mUserManager.getSerialNumberForUser(eq(UserHandle.of(USER_ID)))) + .thenReturn(USER_SERIAL_NUMBER); + + mManager.registerRecoveryAgent(USER_ID, UID); + mManager.registerRecoveryAgent(USER_ID, UID); // ignored. + + verify(mDatabase, times(1)).setUserSerialNumber(USER_ID, USER_SERIAL_NUMBER); + } + + @Test + public void verifyKnownUsers_newSerialNumber_deletesData() throws Exception { + Map knownSerialNumbers = new HashMap<>(); + knownSerialNumbers.put(USER_ID, USER_SERIAL_NUMBER); + when(mDatabase.getUserSerialNumbers()).thenReturn(knownSerialNumbers); + List<Integer> recoveryAgents = new ArrayList<>(); + recoveryAgents.add(UID); + when(mDatabase.getRecoveryAgents(USER_ID)).thenReturn(recoveryAgents); + + when(mUserManager.getSerialNumberForUser(eq(UserHandle.of(USER_ID)))) + .thenReturn(USER_SERIAL_NUMBER_2); // new value + + + mManager.verifyKnownUsers(); + + verify(mDatabase).removeUserFromAllTables(USER_ID); + verify(mDatabase).setUserSerialNumber(USER_ID, USER_SERIAL_NUMBER_2); + verify(mRecoverySnapshotStorage).remove(UID); + } +} + diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java index 35215c34d8f0..2658af68f78b 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java @@ -51,6 +51,7 @@ public class RecoverableKeyStoreDbHelperTest { private static final long TEST_LAST_SYNCED_AT = 1517990732000L; private static final int TEST_RECOVERY_STATUS = 3; private static final int TEST_PLATFORM_KEY_GENERATION_ID = 11; + private static final int TEST_USER_SERIAL_NUMBER = 15; private static final int TEST_SNAPSHOT_VERSION = 31; private static final int TEST_SHOULD_CREATE_SNAPSHOT = 1; private static final byte[] TEST_PUBLIC_KEY = "test-public-key".getBytes(UTF_8); @@ -234,5 +235,14 @@ public class RecoverableKeyStoreDbHelperTest { assertThat(mDatabase.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)) .isGreaterThan(-1L); + + // User serial number column was added when upgrading from v5 to v6 + values = new ContentValues(); + values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID); + values.put(UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER, TEST_USER_SERIAL_NUMBER); + assertThat( + mDatabase.replace(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)) + .isGreaterThan(-1L); } + } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java index 7de9ffc7f3cc..932a769c86bc 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java @@ -279,6 +279,55 @@ public class RecoverableKeyStoreDbTest { } @Test + public void getUserSerialNumbers_returnsSerialNumbers() { + int userId = 42; + int userId2 = 44; + Long serialNumber = 24L; + Long serialNumber2 = 25L; + mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber); + mRecoverableKeyStoreDb.setUserSerialNumber(userId2, serialNumber2); + + assertEquals(2, mRecoverableKeyStoreDb.getUserSerialNumbers().size()); + assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId)); + assertEquals(serialNumber2, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId2)); + } + + @Test + public void getUserSerialNumbers_returnsMinusOneIfNoEntry() { + int userId = 42; + int generationId = 24; + Long serialNumber = -1L; + // Don't set serial number + mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId); + + assertEquals(1, mRecoverableKeyStoreDb.getUserSerialNumbers().size()); + assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId)); + } + + @Test + public void removeUserFromAllTables_removesData() throws Exception { + int userId = 12; + int generationId = 24; + int[] types = new int[]{1}; + int uid = 10009; + mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, + TEST_ROOT_CERT_ALIAS, 1234L); + mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId); + mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root"); + mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types); + + mRecoverableKeyStoreDb.removeUserFromAllTables(userId); + + // RootOfTrust + assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid, + TEST_ROOT_CERT_ALIAS)).isNull(); + // UserMetadata + assertThat(mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId)).isEqualTo(-1); + // RecoveryServiceMetadata + assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEmpty(); + } + + @Test public void setRecoveryStatus_withSingleKey() { int userId = 12; int uid = 1009; diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java index 8caa39dfc9e7..1f861716d380 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java @@ -175,9 +175,9 @@ public class AppTimeLimitControllerTests { /** Verify app usage limit observer is added */ @Test public void testAppUsageLimitObserver_AddObserver() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); - addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID2)); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); } @@ -203,7 +203,7 @@ public class AppTimeLimitControllerTests { /** Verify app usage limit observer is removed */ @Test public void testAppUsageLimitObserver_RemoveObserver() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID); assertFalse("Observer wasn't removed", hasAppUsageLimitObserver(UID, OBS_ID1)); @@ -290,9 +290,9 @@ public class AppTimeLimitControllerTests { /** Re-adding an observer should result in only one copy */ @Test public void testAppUsageLimitObserver_ObserverReAdd() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN); assertTrue("Observer wasn't added", getAppUsageLimitObserver(UID, OBS_ID1).getTimeLimitMs() == TIME_10_MIN); mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID); @@ -304,7 +304,7 @@ public class AppTimeLimitControllerTests { public void testAllObservers_ExclusiveObserverIds() { addAppUsageObserver(OBS_ID1, GROUP1, TIME_10_MIN); addUsageSessionObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_1_MIN); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN); assertTrue("Observer wasn't added", hasAppUsageObserver(UID, OBS_ID1)); assertTrue("Observer wasn't added", hasUsageSessionObserver(UID, OBS_ID1)); assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1)); @@ -396,7 +396,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_Accumulation() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); startUsage(PKG_SOC1); // Add 10 mins setTime(TIME_10_MIN); @@ -456,7 +456,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_TimeoutOtherApp() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L); + addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L); startUsage(PKG_SOC2); assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS)); setTime(6_000L); @@ -498,7 +498,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_Timeout() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L); + addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L); startUsage(PKG_SOC1); setTime(6_000L); assertTrue(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS)); @@ -551,7 +551,7 @@ public class AppTimeLimitControllerTests { setTime(TIME_10_MIN); startUsage(PKG_GAME1); setTime(TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN); setTime(TIME_30_MIN + TIME_10_MIN); stopUsage(PKG_GAME1); assertFalse(mLimitReachedLatch.await(1_000L, TimeUnit.MILLISECONDS)); @@ -612,7 +612,7 @@ public class AppTimeLimitControllerTests { startUsage(PKG_SOC1); setTime(TIME_10_MIN); // 10 second time limit - addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L); + addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L, 10_000L); setTime(TIME_10_MIN + 5_000L); // Shouldn't call back in 6 seconds assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS)); @@ -692,23 +692,23 @@ public class AppTimeLimitControllerTests { public void testAppUsageLimitObserver_MaxObserverLimit() throws Exception { boolean receivedException = false; int ANOTHER_UID = UID + 1; - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN, TIME_30_MIN); // Readding an observer should not cause an IllegalStateException - addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN); // Adding an observer for a different uid shouldn't cause an IllegalStateException mController.addAppUsageLimitObserver( - ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, null, USER_ID); + ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN, null, USER_ID); try { - addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN); } catch (IllegalStateException ise) { receivedException = true; } @@ -748,9 +748,9 @@ public class AppTimeLimitControllerTests { public void testAppUsageLimitObserver_MinimumTimeLimit() throws Exception { boolean receivedException = false; // adding an observer with a one minute time limit should not cause an exception - addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT); + addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT, MIN_TIME_LIMIT); try { - addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1); + addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1, MIN_TIME_LIMIT - 1); } catch (IllegalArgumentException iae) { receivedException = true; } @@ -807,7 +807,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_ConcurrentUsage() throws Exception { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); AppTimeLimitController.UsageGroup group = getAppUsageLimitObserver(UID, OBS_ID1); startUsage(PKG_SOC1); // Add 10 mins @@ -967,7 +967,7 @@ public class AppTimeLimitControllerTests { /** Verify app usage limit observer added correctly reports its total usage limit */ @Test public void testAppUsageLimitObserver_GetTotalUsageLimit() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1); assertNotNull("Observer wasn't added", group); assertEquals("Observer didn't correctly report total usage limit", @@ -978,7 +978,7 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_GetUsageRemaining() { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); startUsage(PKG_SOC1); setTime(TIME_10_MIN); stopUsage(PKG_SOC1); @@ -993,8 +993,8 @@ public class AppTimeLimitControllerTests { */ @Test public void testAppUsageLimitObserver_GetAppUsageLimit() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN); UsageStatsManagerInternal.AppUsageLimitData group = getAppUsageLimit(PKG_SOC1); assertEquals("Observer with the smallest usage limit remaining wasn't returned", TIME_10_MIN, group.getTotalUsageLimit()); @@ -1006,8 +1006,8 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_GetAppUsageLimitUsed() { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN); startUsage(PKG_GAME1); setTime(TIME_10_MIN * 2 + TIME_1_MIN); stopUsage(PKG_GAME1); @@ -1024,8 +1024,8 @@ public class AppTimeLimitControllerTests { @Test public void testAppUsageLimitObserver_GetAppUsageLimitAllUsed() { setTime(0L); - addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN); - addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN); + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN); + addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN); startUsage(PKG_SOC1); setTime(TIME_10_MIN); stopUsage(PKG_SOC1); @@ -1035,10 +1035,21 @@ public class AppTimeLimitControllerTests { 0L, group.getUsageRemaining()); } + /** Verify that a limit of 0 is not allowed. */ + @Test + public void testAppUsageLimitObserver_ZeroTimeLimitIsNotAllowed() { + try { + addAppUsageLimitObserver(OBS_ID1, GROUP1, 0, 0); + fail("timeLimit of 0 should not be allowed."); + } catch (IllegalArgumentException expected) { + // Exception expected. + } + } + /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */ @Test - public void testAppUsageLimitObserver_ZeroTimeLimitIsAllowed() { - addAppUsageLimitObserver(OBS_ID1, GROUP1, 0); + public void testAppUsageLimitObserver_ZeroTimeRemainingIsAllowed() { + addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_1_MIN, 0); AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1); assertNotNull("Observer wasn't added", group); assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining()); @@ -1066,8 +1077,10 @@ public class AppTimeLimitControllerTests { null, null, USER_ID); } - private void addAppUsageLimitObserver(int observerId, String[] packages, long timeLimit) { - mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, null, USER_ID); + private void addAppUsageLimitObserver(int observerId, String[] packages, long timeLimit, + long timeRemaining) { + mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, timeRemaining, + null, USER_ID); } /** Is there still an app usage observer by that id */ 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 606ab31f638e..d02db7b2af22 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -561,7 +561,7 @@ public class ActivityStarterTests extends ActivityTestsBase { runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false); + false, false, false, false, false, false); } /** @@ -576,7 +576,7 @@ public class ActivityStarterTests extends ActivityTestsBase { "disallowed_unsupportedUsecase_aborted", true, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false); + false, false, false, false, false, false); } /** @@ -591,61 +591,66 @@ public class ActivityStarterTests extends ActivityTestsBase { runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false, Process.ROOT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false); + false, false, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false, Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false); + false, false, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false, Process.NFC_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false); + false, false, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callingUidHasVisibleWindow_notAborted", false, UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false); + 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, 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, 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, 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); + 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, - false, true, false, false, false); + false, true, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callerIsWhitelisted_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, true, false, false); + false, false, true, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, true, false); + false, false, false, true, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callingPackageNameIsDeviceOwner_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, true); + false, false, false, false, true, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_callingPackageNameIsTempWhitelisted_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + false, false, false, false, false, true); } private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, @@ -654,7 +659,7 @@ public class ActivityStarterTests extends ActivityTestsBase { boolean hasForegroundActivities, boolean callerIsRecents, boolean callerIsTempWhitelisted, boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, - boolean isCallingPackageNameDeviceOwner) { + boolean isCallingPackageNameDeviceOwner, boolean isCallingPackageTempWhitelisted) { // window visibility doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot) .isAnyNonToastWindowVisibleForUid(callingUid); @@ -680,11 +685,15 @@ public class ActivityStarterTests extends ActivityTestsBase { // caller is instrumenting with background activity starts privileges callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges, callerIsInstrumentingWithBackgroundActivityStartPrivileges); - // calling package name is whitelisted + // calling package name is the device owner doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any()); + // calling package name is temporarily whitelisted + doReturn(isCallingPackageTempWhitelisted).when(mService) + .isPackageNameWhitelistedForBgActivityStarts("com.whatever.dude"); final ActivityOptions options = spy(ActivityOptions.makeBasic()); ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK) + .setCallingPackage("com.whatever.dude") .setCaller(caller) .setCallingUid(callingUid) .setRealCallingUid(realCallingUid) diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java index 731cbf42eca7..f3d63873dc4b 100644 --- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java +++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java @@ -511,8 +511,10 @@ public class AppTimeLimitController { class AppUsageLimitGroup extends UsageGroup { public AppUsageLimitGroup(UserData user, ObserverAppData observerApp, int observerId, - String[] observed, long timeLimitMs, PendingIntent limitReachedCallback) { + String[] observed, long timeLimitMs, long timeRemainingMs, + PendingIntent limitReachedCallback) { super(user, observerApp, observerId, observed, timeLimitMs, limitReachedCallback); + mUsageTimeMs = timeLimitMs - timeRemainingMs; } @Override @@ -839,9 +841,9 @@ public class AppTimeLimitController { * Existing app usage limit observer with the same observerId will be removed. */ public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed, - long timeLimit, PendingIntent callbackIntent, @UserIdInt int userId) { - // Allow the special case of the limit being 0, but with no callback. - if (timeLimit != 0L && timeLimit < getMinTimeLimit()) { + long timeLimit, long timeRemaining, PendingIntent callbackIntent, + @UserIdInt int userId) { + if (timeLimit < getMinTimeLimit()) { throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit()); } synchronized (mLock) { @@ -859,7 +861,7 @@ public class AppTimeLimitController { "Too many app usage observers added by uid " + requestingUid); } group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit, - timeLimit == 0L ? null : callbackIntent); + timeRemaining, timeRemaining == 0L ? null : callbackIntent); observerApp.appUsageLimitGroups.append(observerId, group); if (DEBUG) { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index b14d7228dcb4..27fdbcb80275 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1399,7 +1399,8 @@ public class UsageStatsService extends SystemService implements @Override public void registerAppUsageLimitObserver(int observerId, String[] packages, - long timeLimitMs, PendingIntent callbackIntent, String callingPackage) { + long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent, + String callingPackage) { if (!hasPermissions(callingPackage, Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) { throw new SecurityException("Caller doesn't have both SUSPEND_APPS and " @@ -1409,7 +1410,11 @@ public class UsageStatsService extends SystemService implements if (packages == null || packages.length == 0) { throw new IllegalArgumentException("Must specify at least one package"); } - if (callbackIntent == null && timeLimitMs != 0L) { + if (timeRemainingMs > timeLimitMs) { + throw new IllegalArgumentException( + "Remaining time can't be greater than total time."); + } + if (callbackIntent == null && timeRemainingMs != 0L) { throw new NullPointerException("callbackIntent can't be null"); } final int callingUid = Binder.getCallingUid(); @@ -1417,7 +1422,7 @@ public class UsageStatsService extends SystemService implements final long token = Binder.clearCallingIdentity(); try { UsageStatsService.this.registerAppUsageLimitObserver(callingUid, observerId, - packages, timeLimitMs, callbackIntent, userId); + packages, timeLimitMs, timeRemainingMs, callbackIntent, userId); } finally { Binder.restoreCallingIdentity(token); } @@ -1545,9 +1550,9 @@ public class UsageStatsService extends SystemService implements } void registerAppUsageLimitObserver(int callingUid, int observerId, String[] packages, - long timeLimitMs, PendingIntent callbackIntent, int userId) { - mAppTimeLimit.addAppUsageLimitObserver(callingUid, observerId, packages, timeLimitMs, - callbackIntent, userId); + long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent, int userId) { + mAppTimeLimit.addAppUsageLimitObserver(callingUid, observerId, packages, + timeLimitMs, timeRemainingMs, callbackIntent, userId); } void unregisterAppUsageLimitObserver(int callingUid, int observerId, int userId) { diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp index 5ac4a46b81f1..4359978f5814 100644 --- a/startop/iorap/tests/Android.bp +++ b/startop/iorap/tests/Android.bp @@ -29,7 +29,7 @@ java_library { // test android dependencies "platform-test-annotations", - "android-support-test", + "androidx.test.rules", // test framework dependencies "mockito-target-inline-minus-junit4", // "mockito-target-minus-junit4", diff --git a/startop/iorap/tests/AndroidManifest.xml b/startop/iorap/tests/AndroidManifest.xml index 99f4add6579f..b967e7207a3f 100644 --- a/startop/iorap/tests/AndroidManifest.xml +++ b/startop/iorap/tests/AndroidManifest.xml @@ -22,7 +22,7 @@ <!--suppress AndroidDomInspection --> <instrumentation - android:name="android.support.test.runner.AndroidJUnitRunner" + android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.google.android.startop.iorap.tests" /> <!-- diff --git a/startop/iorap/tests/AndroidTest.xml b/startop/iorap/tests/AndroidTest.xml index 919154d3e48a..bcd11033bed3 100644 --- a/startop/iorap/tests/AndroidTest.xml +++ b/startop/iorap/tests/AndroidTest.xml @@ -44,7 +44,7 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.google.android.startop.iorap.tests" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> </test> </configuration> diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt index 16dcbe20f46a..b1e6194e0c92 100644 --- a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt +++ b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt @@ -14,12 +14,14 @@ package com.google.android.startop.iorap -import android.net.Uri import android.os.ServiceManager -import android.support.test.filters.MediumTest +import androidx.test.filters.MediumTest import org.junit.Test -import org.junit.Ignore -import org.mockito.Mockito.* +import org.mockito.Mockito.argThat +import org.mockito.Mockito.eq +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.spy +import org.mockito.Mockito.timeout // @Ignore("Test is disabled until iorapd is added to init and there's selinux policies for it") @MediumTest @@ -27,7 +29,7 @@ class IIorapIntegrationTest { /** * @throws ServiceManager.ServiceNotFoundException if iorapd service could not be found */ - private val iorapService : IIorap by lazy { + private val iorapService: IIorap by lazy { // TODO: connect to 'iorapd.stub' which doesn't actually do any work other than reply. IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd")) @@ -39,7 +41,7 @@ class IIorapIntegrationTest { // A dummy binder stub implementation is required to use with mockito#spy. // Mockito overrides the methods at runtime and tracks how methods were invoked. - open class DummyTaskListener : ITaskListener.Stub() { + open class DummyTaskListener : ITaskListener.Stub() { // Note: make parameters nullable to avoid the kotlin IllegalStateExceptions // from using the mockito matchers (eq, argThat, etc). override fun onProgress(requestId: RequestId?, result: TaskResult?) { @@ -49,7 +51,7 @@ class IIorapIntegrationTest { } } - private fun testAnyMethod(func : (RequestId) -> Unit) { + private fun testAnyMethod(func: (RequestId) -> Unit) { val taskListener = spy(DummyTaskListener())!! try { @@ -68,14 +70,13 @@ class IIorapIntegrationTest { // The "stub" behavior of iorapd is that every request immediately gets a response of // BEGAN,ONGOING,COMPLETED - inOrder.verify(taskListener, timeout(100)). - onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_BEGAN }) - inOrder.verify(taskListener, timeout(100)). - onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_ONGOING }) - inOrder.verify(taskListener, timeout(100)). - onComplete(eq(requestId), argThat { it!!.state == TaskResult.STATE_COMPLETED }) + inOrder.verify(taskListener, timeout(100)) + .onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_BEGAN }) + inOrder.verify(taskListener, timeout(100)) + .onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_ONGOING }) + inOrder.verify(taskListener, timeout(100)) + .onComplete(eq(requestId), argThat { it!!.state == TaskResult.STATE_COMPLETED }) inOrder.verifyNoMoreInteractions() - } finally { // iorapService.setTaskListener(null) // FIXME: null is broken, C++ side sees a non-null object. @@ -96,7 +97,7 @@ class IIorapIntegrationTest { @Test fun testOnAppIntentEvent() { - testAnyMethod { requestId : RequestId -> + testAnyMethod { requestId: RequestId -> iorapService.onAppIntentEvent(requestId, AppIntentEvent.createDefaultIntentChanged( ActivityInfo("dont care", "dont care"), ActivityInfo("dont care 2", "dont care 2"))) @@ -105,7 +106,7 @@ class IIorapIntegrationTest { @Test fun testOnSystemServiceEvent() { - testAnyMethod { requestId : RequestId -> + testAnyMethod { requestId: RequestId -> iorapService.onSystemServiceEvent(requestId, SystemServiceEvent(SystemServiceEvent.TYPE_START)) } @@ -113,9 +114,9 @@ class IIorapIntegrationTest { @Test fun testOnSystemServiceUserEvent() { - testAnyMethod { requestId : RequestId -> + testAnyMethod { requestId: RequestId -> iorapService.onSystemServiceUserEvent(requestId, - SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER,0)) + SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 0)) } } } diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt index 4abbb3e9f162..8fa0cde0f9cc 100644 --- a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt +++ b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt @@ -17,7 +17,7 @@ package com.google.android.startop.iorap import android.net.Uri import android.os.Parcel import android.os.Parcelable -import android.support.test.filters.SmallTest +import androidx.test.filters.SmallTest import org.junit.Test import org.junit.runner.RunWith import com.google.common.truth.Truth.assertThat @@ -29,7 +29,7 @@ import org.junit.runners.Parameterized */ @SmallTest @RunWith(Parameterized::class) -class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) { +class ParcelablesTest<T : Parcelable>(private val inputData: InputData<T>) { companion object { private val initialRequestId = RequestId.nextValueForSequence()!! @@ -73,19 +73,19 @@ class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) { TaskResult(TaskResult.STATE_ONGOING)) ) - private fun newActivityInfo() : ActivityInfo { + private fun newActivityInfo(): ActivityInfo { return ActivityInfo("some package", "some activity") } - private fun newActivityInfoOther() : ActivityInfo { + private fun newActivityInfoOther(): ActivityInfo { return ActivityInfo("some package 2", "some activity 2") } - private fun newUri() : Uri { + private fun newUri(): Uri { return Uri.parse("https://www.google.com") } - private fun cloneRequestId(requestId: RequestId) : RequestId { + private fun cloneRequestId(requestId: RequestId): RequestId { val constructor = requestId::class.java.declaredConstructors[0] constructor.isAccessible = true return constructor.newInstance(requestId.requestId) as RequestId @@ -108,7 +108,7 @@ class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) { @Test fun testParcelRoundTrip() { // calling writeToParcel and then T::CREATOR.createFromParcel would return the same data. - val assertParcels = { it : T, data : InputData<T> -> + val assertParcels = { it: T, data: InputData<T> -> val parcel = Parcel.obtain() it.writeToParcel(parcel, 0) parcel.setDataPosition(0) // future reads will see all previous writes. @@ -121,7 +121,7 @@ class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) { assertParcels(inputData.validOther, inputData) } - data class InputData<T : Parcelable>(val valid : T, val validCopy : T, val validOther : T) { + data class InputData<T : Parcelable>(val valid: T, val validCopy: T, val validOther: T) { val kls = valid.javaClass init { assertThat(valid).isNotSameAs(validCopy) @@ -130,8 +130,8 @@ class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) { assertThat(validOther.javaClass).isEqualTo(valid.javaClass) } - fun createFromParcel(parcel : Parcel) : T { - val field = kls.getDeclaredField("CREATOR") + fun createFromParcel(parcel: Parcel): T { + val field = kls.getDeclaredField("CREATOR") val creator = field.get(null) as Parcelable.Creator<T> return creator.createFromParcel(parcel) diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp index ac60e966fe43..22a3cfafbc44 100644 --- a/startop/view_compiler/dex_builder_test/Android.bp +++ b/startop/view_compiler/dex_builder_test/Android.bp @@ -43,7 +43,7 @@ android_test { sdk_version: "current", data: [":generate_dex_testcases", ":generate_compiled_layout1", ":generate_compiled_layout2"], static_libs: [ - "android-support-test", + "androidx.test.rules", "guava", ], manifest: "AndroidManifest.xml", diff --git a/startop/view_compiler/dex_builder_test/AndroidManifest.xml b/startop/view_compiler/dex_builder_test/AndroidManifest.xml index 6ac5fc5db345..b33566363286 100644 --- a/startop/view_compiler/dex_builder_test/AndroidManifest.xml +++ b/startop/view_compiler/dex_builder_test/AndroidManifest.xml @@ -22,7 +22,7 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.startop.test" android:label="DexBuilder Tests"/> diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml index 92e2a718bcce..82509b960f24 100644 --- a/startop/view_compiler/dex_builder_test/AndroidTest.xml +++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml @@ -31,6 +31,6 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.startop.test" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> </test> </configuration> diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java index 42d4161ee81e..f7b1674894f5 100644 --- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java @@ -14,18 +14,14 @@ package android.startop.test; -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import com.google.common.io.ByteStreams; -import dalvik.system.InMemoryDexClassLoader; import dalvik.system.PathClassLoader; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; + import org.junit.Assert; import org.junit.Test; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + // Adding tests here requires changes in several other places. See README.md in // the view_compiler directory for more information. public class DexBuilderTest { diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java index a3b1b6c11ac3..3dfb20c2e524 100644 --- a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java @@ -15,18 +15,15 @@ package android.startop.test; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.view.View; -import com.google.common.io.ByteStreams; -import dalvik.system.InMemoryDexClassLoader; + +import androidx.test.InstrumentationRegistry; + import dalvik.system.PathClassLoader; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import org.junit.Assert; + import org.junit.Test; +import java.lang.reflect.Method; + // Adding tests here requires changes in several other places. See README.md in // the view_compiler directory for more information. public class LayoutCompilerTest { diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java index 368f0c67e2b0..3a340053ace3 100644 --- a/telephony/java/android/telephony/CallAttributes.java +++ b/telephony/java/android/telephony/CallAttributes.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -29,15 +30,15 @@ import java.util.Objects; * @hide */ @SystemApi -public class CallAttributes implements Parcelable { +public final class CallAttributes implements Parcelable { private PreciseCallState mPreciseCallState; @NetworkType private int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints private CallQuality mCallQuality; - public CallAttributes(PreciseCallState state, @NetworkType int networkType, - CallQuality callQuality) { + public CallAttributes(@NonNull PreciseCallState state, @NetworkType int networkType, + @NonNull CallQuality callQuality) { this.mPreciseCallState = state; this.mNetworkType = networkType; this.mCallQuality = callQuality; @@ -59,6 +60,7 @@ public class CallAttributes implements Parcelable { /** * Returns the {@link PreciseCallState} of the call. */ + @NonNull public PreciseCallState getPreciseCallState() { return mPreciseCallState; } @@ -96,6 +98,7 @@ public class CallAttributes implements Parcelable { /** * Returns the {#link CallQuality} of the call. */ + @NonNull public CallQuality getCallQuality() { return mCallQuality; } diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java index 47ce632f98c5..78623e74277a 100644 --- a/telephony/java/android/telephony/CarrierRestrictionRules.java +++ b/telephony/java/android/telephony/CarrierRestrictionRules.java @@ -177,7 +177,8 @@ public final class CarrierRestrictionRules implements Parcelable { * @return a list of boolean with the same size as input, indicating if each * {@link CarrierIdentifier} is allowed or not. */ - public List<Boolean> isCarrierIdentifiersAllowed(@NonNull List<CarrierIdentifier> carrierIds) { + public @NonNull List<Boolean> areCarrierIdentifiersAllowed( + @NonNull List<CarrierIdentifier> carrierIds) { ArrayList<Boolean> result = new ArrayList<>(carrierIds.size()); // First calculate the result for each slot independently @@ -332,7 +333,7 @@ public final class CarrierRestrictionRules implements Parcelable { /** * Builder for a {@link CarrierRestrictionRules}. */ - public static class Builder { + public static final class Builder { private final CarrierRestrictionRules mRules; /** {@hide} */ @@ -341,14 +342,14 @@ public final class CarrierRestrictionRules implements Parcelable { } /** build command */ - public CarrierRestrictionRules build() { + public @NonNull CarrierRestrictionRules build() { return mRules; } /** * Indicate that all carriers are allowed. */ - public Builder setAllCarriersAllowed() { + public @NonNull Builder setAllCarriersAllowed() { mRules.mAllowedCarriers.clear(); mRules.mExcludedCarriers.clear(); mRules.mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_ALLOWED; @@ -360,7 +361,8 @@ public final class CarrierRestrictionRules implements Parcelable { * * @param allowedCarriers list of allowed carriers */ - public Builder setAllowedCarriers(List<CarrierIdentifier> allowedCarriers) { + public @NonNull Builder setAllowedCarriers( + @NonNull List<CarrierIdentifier> allowedCarriers) { mRules.mAllowedCarriers = new ArrayList<CarrierIdentifier>(allowedCarriers); return this; } @@ -370,7 +372,8 @@ public final class CarrierRestrictionRules implements Parcelable { * * @param excludedCarriers list of excluded carriers */ - public Builder setExcludedCarriers(List<CarrierIdentifier> excludedCarriers) { + public @NonNull Builder setExcludedCarriers( + @NonNull List<CarrierIdentifier> excludedCarriers) { mRules.mExcludedCarriers = new ArrayList<CarrierIdentifier>(excludedCarriers); return this; } @@ -380,7 +383,7 @@ public final class CarrierRestrictionRules implements Parcelable { * * @param carrierRestrictionDefault prioritized carrier list */ - public Builder setDefaultCarrierRestriction( + public @NonNull Builder setDefaultCarrierRestriction( @CarrierRestrictionDefault int carrierRestrictionDefault) { mRules.mCarrierRestrictionDefault = carrierRestrictionDefault; return this; @@ -391,7 +394,7 @@ public final class CarrierRestrictionRules implements Parcelable { * * @param multiSimPolicy multi SIM policy */ - public Builder setMultiSimPolicy(@MultiSimPolicy int multiSimPolicy) { + public @NonNull Builder setMultiSimPolicy(@MultiSimPolicy int multiSimPolicy) { mRules.mMultiSimPolicy = multiSimPolicy; return this; } diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java index 9614dc52324d..a9d307953ced 100644 --- a/telephony/java/android/telephony/NetworkRegistrationState.java +++ b/telephony/java/android/telephony/NetworkRegistrationState.java @@ -285,6 +285,14 @@ public class NetworkRegistrationState implements Parcelable { } /** + * @hide + * @return {@code true} if in service. + */ + public boolean isInService() { + return mRegState == REG_STATE_HOME || mRegState == REG_STATE_ROAMING; + } + + /** * Set {@link ServiceState.RoamingType roaming type}. This could override * roaming type based on resource overlay or carrier config. * @hide diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java index 4fdfcbe045c3..48c07e8d54e1 100644 --- a/telephony/java/android/telephony/RadioAccessFamily.java +++ b/telephony/java/android/telephony/RadioAccessFamily.java @@ -22,6 +22,7 @@ import android.hardware.radio.V1_4.CellInfo.Info; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.TelephonyManager.PrefNetworkMode; import com.android.internal.telephony.RILConstants; @@ -170,7 +171,8 @@ public class RadioAccessFamily implements Parcelable { }; @UnsupportedAppUsage - public static int getRafFromNetworkType(int type) { + @TelephonyManager.NetworkTypeBitMask + public static int getRafFromNetworkType(@PrefNetworkMode int type) { switch (type) { case RILConstants.NETWORK_MODE_WCDMA_PREF: return GSM | WCDMA; @@ -279,6 +281,7 @@ public class RadioAccessFamily implements Parcelable { } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + @PrefNetworkMode public static int getNetworkTypeFromRaf(int raf) { raf = getAdjustedRaf(raf); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index cf2b1ea1cda8..b37a767e3e11 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1566,6 +1566,7 @@ public class TelephonyManager { * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not * available. */ + @Nullable public String getTypeAllocationCode() { return getTypeAllocationCode(getSlotIndex()); } @@ -1576,6 +1577,7 @@ public class TelephonyManager { * * @param slotIndex of which Type Allocation Code is returned */ + @Nullable public String getTypeAllocationCode(int slotIndex) { ITelephony telephony = getITelephony(); if (telephony == null) return null; @@ -1636,6 +1638,7 @@ public class TelephonyManager { * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not * available. */ + @Nullable public String getManufacturerCode() { return getManufacturerCode(getSlotIndex()); } @@ -1646,6 +1649,7 @@ public class TelephonyManager { * * @param slotIndex of which Type Allocation Code is returned */ + @Nullable public String getManufacturerCode(int slotIndex) { ITelephony telephony = getITelephony(); if (telephony == null) return null; @@ -6005,6 +6009,7 @@ public class TelephonyManager { * @return IMS Service Table or null if not present or not loaded * @hide */ + @Nullable @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst() { @@ -6856,12 +6861,12 @@ public class TelephonyManager { * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId the id of the subscription to set the preferred network type for. - * @param networkType the preferred network type, defined in RILConstants.java. + * @param networkType the preferred network type * @return true on success; false on any failure. * @hide */ @UnsupportedAppUsage - public boolean setPreferredNetworkType(int subId, int networkType) { + public boolean setPreferredNetworkType(int subId, @PrefNetworkMode int networkType) { try { ITelephony telephony = getITelephony(); if (telephony != null) { @@ -10367,12 +10372,6 @@ public class TelephonyManager { @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int numOfSims) { - //only proceed if multi-sim is not restricted - if (!isMultisimSupported()) { - Rlog.e(TAG, "switchMultiSimConfig not possible. It is restricted or not supported."); - return; - } - try { ITelephony telephony = getITelephony(); if (telephony != null) { diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index a4ed7750d417..9d072f008bed 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -19,7 +19,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.content.ContentValues; import android.database.Cursor; -import android.hardware.radio.V1_0.ApnTypes; +import android.hardware.radio.V1_4.ApnTypes; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -79,7 +79,7 @@ public class ApnSetting implements Parcelable { * APN type for all APNs. * @hide */ - public static final int TYPE_ALL = ApnTypes.ALL; + public static final int TYPE_ALL = ApnTypes.ALL | ApnTypes.MCX; /** APN type for default data traffic. */ public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI; /** APN type for MMS traffic. */ @@ -103,6 +103,8 @@ public class ApnSetting implements Parcelable { * for access to carrier services in an emergency call situation. */ public static final int TYPE_EMERGENCY = ApnTypes.EMERGENCY; + /** APN type for MCX (Mission Critical Service) where X can be PTT/Video/Data */ + public static final int TYPE_MCX = ApnTypes.MCX; /** @hide */ @IntDef(flag = true, prefix = { "TYPE_" }, value = { @@ -115,7 +117,8 @@ public class ApnSetting implements Parcelable { TYPE_IMS, TYPE_CBS, TYPE_IA, - TYPE_EMERGENCY + TYPE_EMERGENCY, + TYPE_MCX }) @Retention(RetentionPolicy.SOURCE) public @interface ApnType {} @@ -206,6 +209,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_STRING_MAP.put("cbs", TYPE_CBS); APN_TYPE_STRING_MAP.put("ia", TYPE_IA); APN_TYPE_STRING_MAP.put("emergency", TYPE_EMERGENCY); + APN_TYPE_STRING_MAP.put("mcx", TYPE_MCX); APN_TYPE_INT_MAP = new ArrayMap<Integer, String>(); APN_TYPE_INT_MAP.put(TYPE_DEFAULT, "default"); APN_TYPE_INT_MAP.put(TYPE_MMS, "mms"); @@ -217,6 +221,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_INT_MAP.put(TYPE_CBS, "cbs"); APN_TYPE_INT_MAP.put(TYPE_IA, "ia"); APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, "emergency"); + APN_TYPE_INT_MAP.put(TYPE_MCX, "mcx"); PROTOCOL_STRING_MAP = new ArrayMap<String, Integer>(); PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP); @@ -1833,7 +1838,7 @@ public class ApnSetting implements Parcelable { * {@link ApnSetting} built from this builder otherwise. */ public ApnSetting build() { - if ((mApnTypeBitmask & ApnTypes.ALL) == 0 || TextUtils.isEmpty(mApnName) + if ((mApnTypeBitmask & TYPE_ALL) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { return null; } diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index ad343498f9e1..afbf46d8b7b1 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -17,6 +17,7 @@ package android.telephony.euicc; import android.Manifest; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; @@ -429,6 +430,7 @@ public class EuiccManager { * * @return an EuiccManager that uses the given card ID for all calls. */ + @NonNull public EuiccManager createForCardId(int cardId) { return new EuiccManager(mContext, cardId); } diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java index 337375ac51c3..a09844d6c0e2 100644 --- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java +++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java @@ -16,6 +16,7 @@ package android.telephony.ims; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.RemoteException; import android.telephony.CallQuality; @@ -606,7 +607,7 @@ public class ImsCallSessionListener { * * @param profile updated ImsStreamMediaProfile */ - public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) { + public void callSessionRttAudioIndicatorChanged(@NonNull ImsStreamMediaProfile profile) { try { mListener.callSessionRttAudioIndicatorChanged(profile); } catch (RemoteException e) { @@ -619,7 +620,7 @@ public class ImsCallSessionListener { * * @param callQuality The new call quality */ - public void callQualityChanged(CallQuality callQuality) { + public void callQualityChanged(@NonNull CallQuality callQuality) { try { mListener.callQualityChanged(callQuality); } catch (RemoteException e) { diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java index 10001bc69d17..464db34d0d65 100644 --- a/telephony/java/android/telephony/ims/ImsSsData.java +++ b/telephony/java/android/telephony/ims/ImsSsData.java @@ -17,6 +17,7 @@ package android.telephony.ims; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -24,6 +25,9 @@ import android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * Provides STK Call Control Supplementary Service information. @@ -260,13 +264,13 @@ public final class ImsSsData implements Parcelable { public final int result; private int[] mSsInfo; - private ImsCallForwardInfo[] mCfInfo; - private ImsSsInfo[] mImsSsInfo; + private List<ImsCallForwardInfo> mCfInfo; + private List<ImsSsInfo> mImsSsInfo; /** * Builder for optional ImsSsData parameters. */ - public static class Builder { + public static final class Builder { private ImsSsData mImsSsData; /** @@ -301,7 +305,7 @@ public final class ImsSsData implements Parcelable { * Set the array of {@link ImsSsInfo}s that are associated with this supplementary service * data. */ - public @NonNull Builder setSuppServiceInfo(@NonNull ImsSsInfo[] imsSsInfos) { + public @NonNull Builder setSuppServiceInfo(@NonNull List<ImsSsInfo> imsSsInfos) { mImsSsData.mImsSsInfo = imsSsInfos; return this; } @@ -311,7 +315,7 @@ public final class ImsSsData implements Parcelable { * service data. */ public @NonNull Builder setCallForwardingInfo( - @NonNull ImsCallForwardInfo[] imsCallForwardInfos) { + @NonNull List<ImsCallForwardInfo> imsCallForwardInfos) { mImsSsData.mCfInfo = imsCallForwardInfos; return this; } @@ -360,8 +364,8 @@ public final class ImsSsData implements Parcelable { serviceClass = in.readInt(); result = in.readInt(); mSsInfo = in.createIntArray(); - mCfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader()); - mImsSsInfo = (ImsSsInfo[])in.readParcelableArray(this.getClass().getClassLoader()); + mCfInfo = in.readParcelableList(new ArrayList<>(), this.getClass().getClassLoader()); + mImsSsInfo = in.readParcelableList(new ArrayList<>(), this.getClass().getClassLoader()); } public static final @android.annotation.NonNull Creator<ImsSsData> CREATOR = new Creator<ImsSsData>() { @@ -384,8 +388,8 @@ public final class ImsSsData implements Parcelable { out.writeInt(getServiceClass()); out.writeInt(getResult()); out.writeIntArray(mSsInfo); - out.writeParcelableArray(mCfInfo, 0); - out.writeParcelableArray(mImsSsInfo, 0); + out.writeParcelableList(mCfInfo, 0); + out.writeParcelableList(mImsSsInfo, 0); } @Override @@ -500,12 +504,12 @@ public final class ImsSsData implements Parcelable { /** @hide */ public void setImsSpecificSuppServiceInfo(ImsSsInfo[] imsSsInfo) { - mImsSsInfo = imsSsInfo; + mImsSsInfo = Arrays.asList(imsSsInfo); } /** @hide */ public void setCallForwardingInfo(ImsCallForwardInfo[] cfInfo) { - mCfInfo = cfInfo; + mCfInfo = Arrays.asList(cfInfo); } /** @@ -524,7 +528,7 @@ public final class ImsSsData implements Parcelable { int[] result = new int[2]; - if (mImsSsInfo == null || mImsSsInfo.length == 0) { + if (mImsSsInfo == null || mImsSsInfo.size() == 0) { Rlog.e(TAG, "getSuppServiceInfoCompat: Could not parse mImsSsInfo, returning empty " + "int[]"); return result; @@ -535,26 +539,26 @@ public final class ImsSsData implements Parcelable { if (isTypeClir()) { // Assume there will only be one ImsSsInfo. // contains {"n","m"} parameters - result[0] = mImsSsInfo[0].getClirOutgoingState(); - result[1] = mImsSsInfo[0].getClirInterrogationStatus(); + result[0] = mImsSsInfo.get(0).getClirOutgoingState(); + result[1] = mImsSsInfo.get(0).getClirInterrogationStatus(); return result; } // COLR 7.31 if (isTypeColr()) { - result[0] = mImsSsInfo[0].getProvisionStatus(); + result[0] = mImsSsInfo.get(0).getProvisionStatus(); } // Facility Lock CLCK 7.4 (for call barring), CLIP 7.6, COLP 7.8, as well as any // other result, just return the status for the "n" parameter and provisioning status for // "m" as the default. - result[0] = mImsSsInfo[0].getStatus(); - result[1] = mImsSsInfo[0].getProvisionStatus(); + result[0] = mImsSsInfo.get(0).getStatus(); + result[1] = mImsSsInfo.get(0).getProvisionStatus(); return result; } /** * @return an array of {@link ImsSsInfo}s associated with this supplementary service data. */ - public @NonNull ImsSsInfo[] getSuppServiceInfo() { + public @NonNull List<ImsSsInfo> getSuppServiceInfo() { return mImsSsInfo; } @@ -562,7 +566,7 @@ public final class ImsSsData implements Parcelable { * @return an array of {@link ImsCallForwardInfo}s associated with this supplementary service * data. **/ - public ImsCallForwardInfo[] getCallForwardInfo() { + public @Nullable List<ImsCallForwardInfo> getCallForwardInfo() { return mCfInfo; } diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java index 303a9fee50be..18e7530a790e 100644 --- a/telephony/java/android/telephony/ims/ImsSsInfo.java +++ b/telephony/java/android/telephony/ims/ImsSsInfo.java @@ -173,7 +173,7 @@ public final class ImsSsInfo implements Parcelable { /** * Builds {@link ImsSsInfo} instances, which may include optional parameters. */ - public static class Builder { + public static final class Builder { private final ImsSsInfo mImsSsInfo; @@ -304,7 +304,7 @@ public final class ImsSsInfo implements Parcelable { /** * @return The Incoming Communication Barring (ICB) number. */ - public String getIncomingCommunicationBarringNumber() { + public @Nullable String getIncomingCommunicationBarringNumber() { return mIcbNum; } diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index e87d28c6f9e9..d5061a32ba6d 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -141,6 +141,8 @@ public class PhoneConstants { /** APN type for Emergency PDN. This is not an IA apn, but is used * for access to carrier services in an emergency call situation. */ public static final String APN_TYPE_EMERGENCY = "emergency"; + /** APN type for Mission Critical Services */ + public static final String APN_TYPE_MCX = "mcx"; /** Array of all APN types */ public static final String[] APN_TYPES = {APN_TYPE_DEFAULT, APN_TYPE_MMS, @@ -151,7 +153,8 @@ public class PhoneConstants { APN_TYPE_IMS, APN_TYPE_CBS, APN_TYPE_IA, - APN_TYPE_EMERGENCY + APN_TYPE_EMERGENCY, + APN_TYPE_MCX }; public static final int RIL_CARD_MAX_APPS = 8; diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk index f23a665dc5b2..e1f56b8ba55f 100644 --- a/tests/ActivityManagerPerfTests/tests/Android.mk +++ b/tests/ActivityManagerPerfTests/tests/Android.mk @@ -21,7 +21,7 @@ LOCAL_SRC_FILES := \ $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ + androidx.test.rules \ apct-perftests-utils \ ActivityManagerPerfTestsUtils diff --git a/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml index a1ab33a96248..04aef47419d0 100644 --- a/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml +++ b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml @@ -25,6 +25,6 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.frameworks.perftests.amtests"/> </manifest> diff --git a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml index ffb5404d7d94..76c40b2e3dc6 100644 --- a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml +++ b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml @@ -24,6 +24,6 @@ <option name="test-tag" value="ActivityManagerPerfTests"/> <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.frameworks.perftests.amtests"/> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/> </test> </configuration>
\ No newline at end of file diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java index 58fb136ae9b3..daff76f4f522 100644 --- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java +++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java @@ -21,7 +21,8 @@ import android.content.Intent; import android.content.ServiceConnection; import android.perftests.utils.ManualBenchmarkState; import android.perftests.utils.PerfManualStatusReporter; -import android.support.test.InstrumentationRegistry; + +import androidx.test.InstrumentationRegistry; import com.android.frameworks.perftests.am.util.TargetPackageUtils; import com.android.frameworks.perftests.am.util.TimeReceiver; diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java index f7dab03f10ee..bc528d4d4fb7 100644 --- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java +++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java @@ -17,8 +17,9 @@ package com.android.frameworks.perftests.am.tests; import android.content.Intent; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.perftests.am.util.Constants; diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java index 3bf56ce8b085..8e8221954ad6 100644 --- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java +++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java @@ -17,8 +17,9 @@ package com.android.frameworks.perftests.am.tests; import android.content.ContentProviderClient; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.perftests.am.util.TargetPackageUtils; diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java index e1263db61b8b..996c5a5c5584 100644 --- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java +++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java @@ -21,8 +21,9 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.perftests.am.util.Constants; import com.android.frameworks.perftests.am.util.TargetPackageUtils; diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java index f05f32382e53..ba2064005937 100644 --- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java +++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java @@ -19,8 +19,9 @@ package com.android.frameworks.perftests.am.tests; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.perftests.am.util.Constants; import com.android.frameworks.perftests.am.util.TargetPackageUtils; diff --git a/tests/ActivityManagerPerfTests/utils/Android.mk b/tests/ActivityManagerPerfTests/utils/Android.mk index 60c94239d85f..7a7471dd6cd8 100644 --- a/tests/ActivityManagerPerfTests/utils/Android.mk +++ b/tests/ActivityManagerPerfTests/utils/Android.mk @@ -23,7 +23,7 @@ LOCAL_SRC_FILES := \ src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ + androidx.test.rules \ junit \ ub-uiautomator diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Utils.java b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Utils.java index 67071d204eff..fc787bafa93a 100644 --- a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Utils.java +++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Utils.java @@ -19,10 +19,11 @@ package com.android.frameworks.perftests.am.util; import android.content.Intent; import android.os.RemoteException; import android.os.ResultReceiver; -import android.support.test.InstrumentationRegistry; import android.support.test.uiautomator.UiDevice; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import java.io.IOException; public class Utils { diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk index 1fb548b0edde..f50bca560f83 100644 --- a/tests/AppLaunch/Android.mk +++ b/tests/AppLaunch/Android.mk @@ -12,7 +12,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index 5ea8ff1c4861..9d7319f7d337 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -30,11 +30,12 @@ import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; -import android.support.test.rule.logging.AtraceLogger; import android.test.InstrumentationTestCase; import android.test.InstrumentationTestRunner; import android.util.Log; +import androidx.test.rule.logging.AtraceLogger; + import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -51,6 +52,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; + /** * This test is intended to measure the time it takes for the apps to start. * Names of the applications are passed in command line, and the diff --git a/tests/AppLaunchWear/Android.mk b/tests/AppLaunchWear/Android.mk index 6d083661324d..332b6808ace8 100644 --- a/tests/AppLaunchWear/Android.mk +++ b/tests/AppLaunchWear/Android.mk @@ -12,7 +12,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java index d36d84e8f51d..97701c61011e 100644 --- a/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java @@ -30,16 +30,16 @@ import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; -import android.support.test.rule.logging.AtraceLogger; import android.test.InstrumentationTestCase; import android.test.InstrumentationTestRunner; import android.util.Log; +import androidx.test.rule.logging.AtraceLogger; + import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -52,6 +52,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; + /** * This test is intended to measure the time it takes for the apps to start. * Names of the applications are passed in command line, and the diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk index b10305d96fce..f47cf96446ba 100644 --- a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk +++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk @@ -24,7 +24,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ + androidx.test.rules \ LOCAL_PACKAGE_NAME := BackgroundDexOptServiceIntegrationTests LOCAL_PRIVATE_PLATFORM_APIS := true diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml index afae155f88fe..aec9f77cf922 100644 --- a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml +++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml @@ -34,7 +34,7 @@ </application> <instrumentation - android:name="android.support.test.runner.AndroidJUnitRunner" + android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.frameworks.bgdexopttest" android:label="Integration test for BackgroundDexOptService" /> </manifest> diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml index 9bb1e280b861..a532422a38d3 100644 --- a/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml +++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml @@ -50,6 +50,6 @@ <option name="test-tag" value="BackgroundDexOptServiceIntegrationTests"/> <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.frameworks.bgdexopttest"/> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/> </test> </configuration> diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java index fd20f4a1fa77..7d826f7172da 100644 --- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java +++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java @@ -17,17 +17,16 @@ package com.android.server.pm; import android.app.AlarmManager; -import android.app.UiAutomation; import android.content.Context; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.SystemProperties; import android.os.storage.StorageManager; -import android.support.test.InstrumentationRegistry; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import org.junit.After; -import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk index eb8f6c306862..fe4dc42aa7d9 100644 --- a/tests/Camera2Tests/CameraToo/tests/Android.mk +++ b/tests/Camera2Tests/CameraToo/tests/Android.mk @@ -20,6 +20,6 @@ LOCAL_PACKAGE_NAME := CameraTooTests LOCAL_INSTRUMENTATION_FOR := CameraToo LOCAL_SDK_VERSION := current LOCAL_SRC_FILES := $(call all-java-files-under,src) -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4 +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules mockito-target-minus-junit4 include $(BUILD_PACKAGE) diff --git a/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml index 30210bae5cd1..8d3574929ca8 100644 --- a/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml +++ b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml @@ -23,7 +23,7 @@ <application android:label="CameraToo"> <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.example.android.camera2.cameratoo" android:label="CameraToo tests" /> </manifest> diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk index 9c47a2610223..643f9ebd5f15 100644 --- a/tests/Compatibility/Android.mk +++ b/tests/Compatibility/Android.mk @@ -17,7 +17,7 @@ include $(CLEAR_VARS) # We only want this apk build for tests. LOCAL_MODULE_TAGS := tests -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules # Include all test java files. LOCAL_SRC_FILES := \ $(call all-java-files-under, src) diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java index 95eb5c9e7770..d683ec746a61 100644 --- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java +++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java @@ -33,10 +33,11 @@ import android.os.Bundle; import android.os.DropBoxManager; import android.os.RemoteException; import android.os.ServiceManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; import android.util.Log; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + import org.junit.After; import org.junit.Assert; import org.junit.Before; diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java index b61ec346f041..960ea4966958 100644 --- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java +++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibilityRunner.java @@ -16,7 +16,7 @@ package com.android.compatibilitytest; -import android.support.test.runner.AndroidJUnitRunner; +import androidx.test.runner.AndroidJUnitRunner; // empty subclass to maintain backwards compatibility on host-side harness public class AppCompatibilityRunner extends AndroidJUnitRunner {} diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk index f324eb10a7b0..62c1ba89653c 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk @@ -67,7 +67,7 @@ LOCAL_CERTIFICATE := shared LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm) LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ + androidx.test.rules \ truth-prebuilt \ # Include both versions of the .so if we have 2 arch diff --git a/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml index 4327da2db3dd..08fac300512b 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml +++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml @@ -29,7 +29,7 @@ </application> <instrumentation - android:name="android.support.test.runner.AndroidJUnitRunner" + android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.frameworks.dynamiccodeloggertest" android:label="Integration test for DynamicCodeLogger" /> </manifest> diff --git a/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml index f70b9c8cb357..f8a1ec90a78a 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml +++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml @@ -24,7 +24,7 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.frameworks.dynamiccodeloggertest"/> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/> <option name="hidden-api-checks" value="false"/> </test> </configuration> diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java index 4f9aeea5bdb4..db2f659c655b 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java +++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java @@ -24,11 +24,12 @@ import android.content.Context; import android.os.Build; import android.os.ParcelFileDescriptor; import android.os.SystemClock; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; import android.util.EventLog; import android.util.EventLog.Event; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + import dalvik.system.DexClassLoader; import org.junit.Before; diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml index ba6394008642..5b1a36b84cc4 100644 --- a/tests/FlickerTests/AndroidManifest.xml +++ b/tests/FlickerTests/AndroidManifest.xml @@ -29,7 +29,7 @@ <uses-library android:name="android.test.runner"/> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.server.wm.flicker" android:label="WindowManager Flicker Tests"> </instrumentation> diff --git a/tests/FlickerTests/lib/Android.mk b/tests/FlickerTests/lib/Android.mk index 6a8dfe8b5d0a..e438822a6f32 100644 --- a/tests/FlickerTests/lib/Android.mk +++ b/tests/FlickerTests/lib/Android.mk @@ -24,7 +24,7 @@ LOCAL_CERTIFICATE := platform LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ - ub-janktesthelper \ + androidx.test.janktesthelper \ cts-amwm-util \ platformprotosnano \ layersprotosnano \ @@ -41,7 +41,7 @@ LOCAL_SRC_FILES := src/com/android/server/wm/flicker/AutomationUtils.java \ src/com/android/server/wm/flicker/WindowUtils.java LOCAL_STATIC_JAVA_LIBRARIES := sysui-helper \ launcher-helper-lib \ - compatibility-device-util + compatibility-device-util-axt include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AutomationUtils.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AutomationUtils.java index 6306f0e16375..e00a2474556c 100644 --- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AutomationUtils.java +++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AutomationUtils.java @@ -30,7 +30,6 @@ import android.content.pm.PackageManager; import android.graphics.Point; import android.graphics.Rect; import android.os.RemoteException; -import android.support.test.InstrumentationRegistry; import android.support.test.launcherhelper.LauncherStrategyFactory; import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; @@ -43,6 +42,8 @@ import android.util.Rational; import android.view.View; import android.view.ViewConfiguration; +import androidx.test.InstrumentationRegistry; + /** * Collection of UI Automation helper functions. */ diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java index f6e8192ee4c0..0a3fe3c00de2 100644 --- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java +++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java @@ -18,9 +18,10 @@ package com.android.server.wm.flicker; import android.annotation.Nullable; import android.support.annotation.VisibleForTesting; -import android.support.test.InstrumentationRegistry; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import com.android.server.wm.flicker.monitor.ITransitionMonitor; import com.android.server.wm.flicker.monitor.LayersTraceMonitor; import com.android.server.wm.flicker.monitor.ScreenRecorder; diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java index 0da876173995..c54396f895e4 100644 --- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java +++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java @@ -20,10 +20,11 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; -import android.support.test.InstrumentationRegistry; import android.view.Surface; import android.view.WindowManager; +import androidx.test.InstrumentationRegistry; + /** * Helper functions to retrieve system window sizes and positions. */ diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitor.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitor.java index 717d187e1d4a..3f86f0d001d7 100644 --- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitor.java +++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitor.java @@ -25,7 +25,7 @@ import android.view.FrameStats; /** * Monitors {@link android.view.WindowAnimationFrameStats} to detect janky frames. * - * Adapted from {@link android.support.test.jank.internal.WindowAnimationFrameStatsMonitorImpl} + * Adapted from {@link androidx.test.jank.internal.WindowAnimationFrameStatsMonitorImpl} * using the same threshold to determine jank. */ public class WindowAnimationFrameStatsMonitor implements ITransitionMonitor { diff --git a/tests/FlickerTests/lib/test/Android.mk b/tests/FlickerTests/lib/test/Android.mk index 0e3f58d8a8c9..5be89ba624e6 100644 --- a/tests/FlickerTests/lib/test/Android.mk +++ b/tests/FlickerTests/lib/test/Android.mk @@ -25,7 +25,7 @@ LOCAL_COMPATIBILITY_SUITE := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ + androidx.test.rules \ platform-test-annotations \ truth-prebuilt \ platformprotosnano \ diff --git a/tests/FlickerTests/lib/test/AndroidManifest.xml b/tests/FlickerTests/lib/test/AndroidManifest.xml index d30172d56c2c..6451a5710821 100644 --- a/tests/FlickerTests/lib/test/AndroidManifest.xml +++ b/tests/FlickerTests/lib/test/AndroidManifest.xml @@ -18,7 +18,7 @@ <uses-library android:name="android.test.runner"/> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.server.wm.flicker" android:label="WindowManager Flicker Lib Test"> </instrumentation> diff --git a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/LayersTraceTest.java b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/LayersTraceTest.java index 42b2acace8c9..7d77126fd7d4 100644 --- a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/LayersTraceTest.java +++ b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/LayersTraceTest.java @@ -26,9 +26,10 @@ import static org.junit.Assert.fail; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; -import android.support.test.InstrumentationRegistry; import android.view.WindowManager; +import androidx.test.InstrumentationRegistry; + import org.junit.Test; import java.util.List; diff --git a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/TestFileUtils.java b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/TestFileUtils.java index 5a24e6d91595..c46175c1a977 100644 --- a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/TestFileUtils.java +++ b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/TestFileUtils.java @@ -17,7 +17,8 @@ package com.android.server.wm.flicker; import android.content.Context; -import android.support.test.InstrumentationRegistry; + +import androidx.test.InstrumentationRegistry; import com.google.common.io.ByteStreams; diff --git a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java index f7fa0d572de6..dd6fed04d3e6 100644 --- a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java +++ b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java @@ -18,9 +18,7 @@ package com.android.server.wm.flicker.monitor; import static com.android.server.wm.flicker.AutomationUtils.wakeUpAndGoToHomeScreen; -import static com.google.common.truth.Truth.assertThat; - -import android.support.test.InstrumentationRegistry; +import androidx.test.InstrumentationRegistry; import org.junit.Before; import org.junit.Ignore; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java index 34f4ebb89543..b6860cbd8d96 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java @@ -25,11 +25,12 @@ import static com.android.server.wm.flicker.WindowUtils.getStatusBarPosition; import static com.android.server.wm.flicker.WmTraceSubject.assertThat; import android.graphics.Rect; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; import android.util.Log; import android.view.Surface; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java index 2b62fcf196fb..6590b86f1499 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java @@ -20,9 +20,10 @@ import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusT import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; import android.platform.helpers.IAppHelper; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java index 42b161f8a604..4771b02000c0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java @@ -20,9 +20,10 @@ import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusT import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; import android.platform.helpers.IAppHelper; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java index 92bb1ea0b58f..65888acc184b 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java @@ -30,7 +30,6 @@ import android.content.Context; import android.content.Intent; import android.os.RemoteException; import android.platform.helpers.IAppHelper; -import android.support.test.InstrumentationRegistry; import android.support.test.uiautomator.By; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; @@ -38,6 +37,8 @@ import android.support.test.uiautomator.Until; import android.util.Rational; import android.view.Surface; +import androidx.test.InstrumentationRegistry; + import com.android.server.wm.flicker.TransitionRunner.TransitionBuilder; /** diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java index fec248c13818..61cca0d6b53f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java @@ -17,12 +17,13 @@ package com.android.server.wm.flicker; import android.platform.helpers.IAppHelper; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; import android.support.test.uiautomator.UiDevice; import android.util.Rational; import android.view.Surface; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java index 7061b23c069d..00e11c0cef41 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java @@ -21,10 +21,11 @@ import static com.android.server.wm.flicker.AutomationUtils.setDefaultWait; import static com.google.common.truth.Truth.assertWithMessage; import android.platform.helpers.IAppHelper; -import android.support.test.InstrumentationRegistry; import android.support.test.uiautomator.UiDevice; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import com.android.server.wm.flicker.TransitionRunner.TransitionResult; import org.junit.After; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java index 7e713699c72e..7818c4e4ba50 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java @@ -20,9 +20,9 @@ import static com.android.server.wm.flicker.CommonTransitions.getOpenAppCold; import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; import static com.android.server.wm.flicker.WmTraceSubject.assertThat; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java index 745569aac7ab..63018ec1d9e7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java @@ -19,9 +19,9 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.appToSplitScreen; import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java index de7639d43d3c..1aba93056c89 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java @@ -20,9 +20,9 @@ import static com.android.server.wm.flicker.CommonTransitions.openAppWarm; import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; import static com.android.server.wm.flicker.WmTraceSubject.assertThat; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java index 1bd519c8334e..a81fa8e6d123 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java @@ -19,8 +19,8 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.editTextSetFocus; import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java index 8a15cbdb7709..50dba81e53b7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java @@ -25,11 +25,12 @@ import static com.google.common.truth.Truth.assertThat; import android.graphics.Rect; import android.platform.helpers.IAppHelper; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; import android.util.Rational; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java index 3eab68d1272f..117ac5a8fadf 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java @@ -27,10 +27,11 @@ import static com.android.server.wm.flicker.testapp.ActivityOptions.SEAMLESS_ACT import android.content.Intent; import android.graphics.Rect; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; import android.view.Surface; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java index 40bd4e962153..1d30df9750b2 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java @@ -19,10 +19,10 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.splitScreenToLauncher; import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.FlakyTest; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/tests/Internal/Android.mk b/tests/Internal/Android.mk index da566967fbeb..2e26ef103794 100644 --- a/tests/Internal/Android.mk +++ b/tests/Internal/Android.mk @@ -11,7 +11,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := junit \ - android-support-test \ + androidx.test.rules \ mockito-target-minus-junit4 LOCAL_JAVA_RESOURCE_DIRS := res diff --git a/tests/Internal/AndroidManifest.xml b/tests/Internal/AndroidManifest.xml index e5a56949fe4e..c85c3b12504a 100644 --- a/tests/Internal/AndroidManifest.xml +++ b/tests/Internal/AndroidManifest.xml @@ -38,7 +38,7 @@ </service> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.internal.tests" android:label="Internal Tests" /> </manifest> diff --git a/tests/Internal/AndroidTest.xml b/tests/Internal/AndroidTest.xml index 6531c9355e3d..7b67e9ebcced 100644 --- a/tests/Internal/AndroidTest.xml +++ b/tests/Internal/AndroidTest.xml @@ -24,6 +24,6 @@ <option name="test-tag" value="InternalTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.internal.tests" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> </test> </configuration>
\ No newline at end of file diff --git a/tests/Internal/src/android/app/WallpaperColorsTest.java b/tests/Internal/src/android/app/WallpaperColorsTest.java index 881f6284413f..65ff6eb1ba04 100644 --- a/tests/Internal/src/android/app/WallpaperColorsTest.java +++ b/tests/Internal/src/android/app/WallpaperColorsTest.java @@ -20,8 +20,9 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Assert; import org.junit.Test; diff --git a/tests/Internal/src/android/app/WallpaperInfoTest.java b/tests/Internal/src/android/app/WallpaperInfoTest.java index 7f06f2cb7aeb..476b99155672 100644 --- a/tests/Internal/src/android/app/WallpaperInfoTest.java +++ b/tests/Internal/src/android/app/WallpaperInfoTest.java @@ -26,9 +26,10 @@ import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Parcel; import android.service.wallpaper.WallpaperService; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java index b9e282ebdfef..592aa3ac4a6b 100644 --- a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java +++ b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import android.support.test.filters.SmallTest; +import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java index 39608a40b416..17fa93135c7d 100644 --- a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java +++ b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java @@ -27,9 +27,10 @@ import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; import android.graphics.Color; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.colorextraction.types.ExtractionType; diff --git a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java index a7d5ae8f69a3..d92cfce0379b 100644 --- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java +++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java @@ -20,11 +20,12 @@ import static org.junit.Assert.assertTrue; import android.app.WallpaperColors; import android.graphics.Color; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; import android.util.Range; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.graphics.ColorUtils; diff --git a/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java b/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java index 73df9a09ea75..d0bb8e3745bc 100644 --- a/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java +++ b/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java @@ -16,12 +16,13 @@ package com.android.internal.graphics; +import static org.junit.Assert.assertTrue; + import android.graphics.Color; -import android.support.test.filters.SmallTest; -import org.junit.Test; +import androidx.test.filters.SmallTest; -import static org.junit.Assert.assertTrue; +import org.junit.Test; @SmallTest public class ColorUtilsTest { diff --git a/tests/Internal/src/com/android/internal/ml/clustering/KMeansTest.java b/tests/Internal/src/com/android/internal/ml/clustering/KMeansTest.java index a64f8a60d485..540a1ec2bd5a 100644 --- a/tests/Internal/src/com/android/internal/ml/clustering/KMeansTest.java +++ b/tests/Internal/src/com/android/internal/ml/clustering/KMeansTest.java @@ -20,8 +20,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.annotation.SuppressLint; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Assert; import org.junit.Before; diff --git a/tests/PackageWatchdog/Android.mk b/tests/PackageWatchdog/Android.mk index 1c1c2a426d15..1e4aacce1613 100644 --- a/tests/PackageWatchdog/Android.mk +++ b/tests/PackageWatchdog/Android.mk @@ -22,7 +22,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_STATIC_JAVA_LIBRARIES := \ junit \ frameworks-base-testutils \ - android-support-test \ + androidx.test.rules \ services.core LOCAL_JAVA_LIBRARIES := \ diff --git a/tests/PackageWatchdog/AndroidManifest.xml b/tests/PackageWatchdog/AndroidManifest.xml index fa89528403c3..540edb41f66f 100644 --- a/tests/PackageWatchdog/AndroidManifest.xml +++ b/tests/PackageWatchdog/AndroidManifest.xml @@ -22,7 +22,7 @@ </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.tests.packagewatchdog" android:label="PackageWatchdog Test"/> </manifest> diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 77cd62e4cbd3..598f60ad7c8d 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -24,7 +24,8 @@ import static org.junit.Assert.assertTrue; import android.content.pm.VersionedPackage; import android.os.test.TestLooper; -import android.support.test.InstrumentationRegistry; + +import androidx.test.InstrumentationRegistry; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; diff --git a/tests/RcsTests/Android.mk b/tests/RcsTests/Android.mk index 7b348d73747a..a276584530f4 100644 --- a/tests/RcsTests/Android.mk +++ b/tests/RcsTests/Android.mk @@ -11,7 +11,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base -LOCAL_STATIC_JAVA_LIBRARIES := junit android-support-test mockito-target-minus-junit4 truth-prebuilt +LOCAL_STATIC_JAVA_LIBRARIES := junit androidx.test.rules mockito-target-minus-junit4 truth-prebuilt include $(BUILD_PACKAGE) diff --git a/tests/RcsTests/AndroidManifest.xml b/tests/RcsTests/AndroidManifest.xml index a7e7d479a4d9..b1706a0a3629 100644 --- a/tests/RcsTests/AndroidManifest.xml +++ b/tests/RcsTests/AndroidManifest.xml @@ -6,6 +6,6 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.tests.rcs"/> </manifest> diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java index 89d32ab5a925..e8989424de6d 100644 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java +++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java @@ -19,10 +19,11 @@ import static com.google.common.truth.Truth.assertThat; import android.net.Uri; import android.os.Parcel; -import android.support.test.runner.AndroidJUnit4; import android.telephony.ims.RcsGroupThreadIconChangedEvent; import android.telephony.ims.RcsGroupThreadIconChangedEventDescriptor; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java index 726b9cd6641f..356688d4db81 100644 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java +++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java @@ -18,10 +18,11 @@ package com.android.tests.ims; import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; -import android.support.test.runner.AndroidJUnit4; import android.telephony.ims.RcsGroupThreadNameChangedEvent; import android.telephony.ims.RcsGroupThreadNameChangedEventDescriptor; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java index a109310076d2..572fcb8ffd5e 100644 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java +++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java @@ -18,10 +18,11 @@ package com.android.tests.ims; import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; -import android.support.test.runner.AndroidJUnit4; import android.telephony.ims.RcsGroupThreadParticipantJoinedEvent; import android.telephony.ims.RcsGroupThreadParticipantJoinedEventDescriptor; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java index de2688c5b8c8..038b2e8e60e3 100644 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java +++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java @@ -18,10 +18,11 @@ package com.android.tests.ims; import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; -import android.support.test.runner.AndroidJUnit4; import android.telephony.ims.RcsGroupThreadParticipantLeftEvent; import android.telephony.ims.RcsGroupThreadParticipantLeftEventDescriptor; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java index 57240545e5d8..283c71b38eef 100644 --- a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java +++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java @@ -18,10 +18,11 @@ package com.android.tests.ims; import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; -import android.support.test.runner.AndroidJUnit4; import android.telephony.ims.RcsParticipantAliasChangedEvent; import android.telephony.ims.RcsParticipantAliasChangedEventDescriptor; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java index 6361a393187e..2d95513be069 100644 --- a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java +++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java @@ -18,9 +18,10 @@ package com.android.tests.ims; import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; -import android.support.test.runner.AndroidJUnit4; import android.telephony.ims.RcsParticipantQueryParams; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java index beb4f8ad28e2..fb51bdaa88a5 100644 --- a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java +++ b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java @@ -21,10 +21,11 @@ import static android.telephony.ims.RcsThreadQueryParams.THREAD_TYPE_GROUP; import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; -import android.support.test.runner.AndroidJUnit4; import android.telephony.ims.RcsParticipant; import android.telephony.ims.RcsThreadQueryParams; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk index db9376b844f9..206f8671d497 100644 --- a/tests/RollbackTest/Android.mk +++ b/tests/RollbackTest/Android.mk @@ -107,7 +107,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under, RollbackTest/src) LOCAL_PACKAGE_NAME := RollbackTest LOCAL_MODULE_TAGS := tests -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_JAVA_RESOURCE_FILES := \ $(ROLLBACK_TEST_APP_AV1) \ diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml index ac39f853656a..70cd86783d6d 100644 --- a/tests/RollbackTest/RollbackTest.xml +++ b/tests/RollbackTest/RollbackTest.xml @@ -20,7 +20,7 @@ </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.tests.rollback" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <!-- Exclude the StagedRollbackTest tests, which needs to be specially driven from the StagedRollbackTest host test --> diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml index e57a768ad1b5..5380dc9fc8cd 100644 --- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml +++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml @@ -24,7 +24,7 @@ </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.tests.rollback" android:label="Rollback Test"/> diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java index ddcf1dabcafc..267ef7377b36 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java @@ -21,7 +21,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentSender; -import android.support.test.InstrumentationRegistry; + +import androidx.test.InstrumentationRegistry; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java index e10f866c899f..8a925b9bad38 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java @@ -20,9 +20,10 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.support.test.InstrumentationRegistry; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index a6054e8f41d0..7e183db58fb4 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -21,6 +21,11 @@ import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEqu import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage; import static com.android.tests.rollback.RollbackTestUtils.processUserData; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import android.Manifest; import android.app.ActivityManager; import android.content.BroadcastReceiver; @@ -31,13 +36,9 @@ import android.content.pm.VersionedPackage; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.provider.DeviceConfig; -import android.support.test.InstrumentationRegistry; import android.util.Log; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import androidx.test.InstrumentationRegistry; import org.junit.Test; import org.junit.runner.RunWith; @@ -378,6 +379,83 @@ public class RollbackTest { // Check that the data has expired after the expiration time (with a buffer of 1 second) Thread.sleep(expirationTime / 2); assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + + } finally { + DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE, + DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, + Long.toString(defaultExpirationTime), false /* makeDefault*/); + RollbackTestUtils.dropShellPermissionIdentity(); + } + } + + /** + * Test that changing time on device does not affect the duration of time that we keep + * rollback available + */ + @Test + public void testTimeChangeDoesNotAffectLifetime() throws Exception { + long expirationTime = TimeUnit.SECONDS.toMillis(30); + long defaultExpirationTime = TimeUnit.HOURS.toMillis(48); + RollbackManager rm = RollbackTestUtils.getRollbackManager(); + + try { + RollbackTestUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.WRITE_DEVICE_CONFIG, + Manifest.permission.SET_TIME); + + DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE, + DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, + Long.toString(expirationTime), false /* makeDefault*/); + + // Pull the new expiration time from DeviceConfig + rm.reloadPersistedData(); + + // Install app A with rollback enabled + RollbackTestUtils.uninstall(TEST_APP_A); + RollbackTestUtils.install("RollbackTestAppAv1.apk", false); + RollbackTestUtils.install("RollbackTestAppAv2.apk", true); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + Thread.sleep(expirationTime / 2); + + // Install app B with rollback enabled + RollbackTestUtils.uninstall(TEST_APP_B); + RollbackTestUtils.install("RollbackTestAppBv1.apk", false); + RollbackTestUtils.install("RollbackTestAppBv2.apk", true); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + // 1 second buffer + Thread.sleep(1000); + + try { + // Change the time + RollbackTestUtils.forwardTimeBy(expirationTime); + + // 1 second buffer to allow Rollback Manager to handle time change before loading + // persisted data + Thread.sleep(1000); + + // Load timestamps from storage + rm.reloadPersistedData(); + + // Wait until rollback for app A has expired + // This will trigger an expiration run that should expire app A but not B + Thread.sleep(expirationTime / 2); + assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + + // Rollback for app B should not be expired + RollbackInfo rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TEST_APP_B); + assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollback); + + // Wait until rollback for app B has expired + Thread.sleep(expirationTime / 2); + assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B)); + } finally { + RollbackTestUtils.forwardTimeBy(-expirationTime); + } } finally { DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE, DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS, diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java index 2f989f316ea6..ed8a53364ec6 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java @@ -16,6 +16,12 @@ package com.android.tests.rollback; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -30,13 +36,9 @@ import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.os.Handler; import android.os.HandlerThread; -import android.support.test.InstrumentationRegistry; import android.util.Log; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import androidx.test.InstrumentationRegistry; import java.io.IOException; import java.io.InputStream; @@ -62,6 +64,17 @@ class RollbackTestUtils { return rm; } + private static void setTime(long millis) { + Context context = InstrumentationRegistry.getContext(); + AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + am.setTime(millis); + } + + static void forwardTimeBy(long offsetMillis) { + setTime(System.currentTimeMillis() + offsetMillis); + Log.i(TAG, "Forwarded time on device by " + offsetMillis + " millis"); + } + /** * Returns the version of the given package installed on device. * Returns -1 if the package is not currently installed. diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk index d1f6450e84a6..617ee7caf139 100644 --- a/tests/ServiceCrashTest/Android.mk +++ b/tests/ServiceCrashTest/Android.mk @@ -12,7 +12,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.base -LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test +LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt androidx.test.rules include $(BUILD_PACKAGE) diff --git a/tests/UsageStatsPerfTests/Android.mk b/tests/UsageStatsPerfTests/Android.mk index cd29b51e5a24..4304fb0d8e9e 100644 --- a/tests/UsageStatsPerfTests/Android.mk +++ b/tests/UsageStatsPerfTests/Android.mk @@ -21,7 +21,7 @@ LOCAL_SRC_FILES := \ $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ + androidx.test.rules \ apct-perftests-utils \ services.usage diff --git a/tests/UsageStatsPerfTests/AndroidManifest.xml b/tests/UsageStatsPerfTests/AndroidManifest.xml index 596a79cd8948..98915485c7bd 100644 --- a/tests/UsageStatsPerfTests/AndroidManifest.xml +++ b/tests/UsageStatsPerfTests/AndroidManifest.xml @@ -24,6 +24,6 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.frameworks.perftests.usage"/> </manifest> diff --git a/tests/UsageStatsPerfTests/AndroidTest.xml b/tests/UsageStatsPerfTests/AndroidTest.xml index c9b51dc5ba07..b8892ebc2ff7 100644 --- a/tests/UsageStatsPerfTests/AndroidTest.xml +++ b/tests/UsageStatsPerfTests/AndroidTest.xml @@ -23,6 +23,6 @@ <option name="test-tag" value="UsageStatsPerfTests"/> <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.frameworks.perftests.usage"/> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/> </test> </configuration>
\ No newline at end of file diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java index e2a4c26606bf..7d9d0d52b002 100644 --- a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java +++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java @@ -24,9 +24,10 @@ import android.content.Context; import android.os.SystemClock; import android.perftests.utils.ManualBenchmarkState; import android.perftests.utils.PerfManualStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.server.usage.IntervalStats; import com.android.server.usage.UsageStatsDatabase; diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java index 0105893adf9e..adcd11a08bff 100644 --- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java @@ -41,6 +41,7 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -196,8 +197,8 @@ public class UsageStatsActivity extends ListActivity { intent.setPackage(getPackageName()); intent.putExtra(EXTRA_KEY_TIMEOUT, true); mUsageStatsManager.registerAppUsageLimitObserver(1, packages, - 60, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this, - 1, intent, 0)); + Duration.ofSeconds(60), Duration.ofSeconds(60), + PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, 0)); } } }); diff --git a/tests/UsbTests/Android.mk b/tests/UsbTests/Android.mk index 4e215cc5996f..aef993b9d348 100644 --- a/tests/UsbTests/Android.mk +++ b/tests/UsbTests/Android.mk @@ -24,7 +24,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_STATIC_JAVA_LIBRARIES := \ frameworks-base-testutils \ - android-support-test \ + androidx.test.rules \ mockito-target-inline-minus-junit4 \ platform-test-annotations \ services.core \ diff --git a/tests/UsbTests/AndroidManifest.xml b/tests/UsbTests/AndroidManifest.xml index 5d606951bb5e..03d1a3ee25e2 100644 --- a/tests/UsbTests/AndroidManifest.xml +++ b/tests/UsbTests/AndroidManifest.xml @@ -24,7 +24,7 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.server.usb" android:label="UsbTests"/> </manifest> diff --git a/tests/UsbTests/AndroidTest.xml b/tests/UsbTests/AndroidTest.xml index 4affad39b4eb..e55bc98ecdc1 100644 --- a/tests/UsbTests/AndroidTest.xml +++ b/tests/UsbTests/AndroidTest.xml @@ -24,7 +24,7 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.server.usb"/> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/> <option name="hidden-api-checks" value="false"/> </test> </configuration> diff --git a/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java index ea027d7ae049..89dc79c08261 100644 --- a/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java +++ b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java @@ -16,29 +16,29 @@ package com.android.server.usb; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import com.android.server.usb.descriptors.UsbDescriptorParser; -import com.android.server.usb.descriptors.UsbDeviceDescriptor; -import com.google.common.io.ByteStreams; -import java.io.InputStream; -import java.io.IOException; -import java.lang.Exception; +import com.google.common.io.ByteStreams; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.IOException; +import java.io.InputStream; + /** * Tests for {@link com.android.server.usb.descriptors.UsbDescriptorParser} */ diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java index 4b93ca3dcaa9..ca1eb705e457 100644 --- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java +++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java @@ -31,11 +31,11 @@ import android.hardware.usb.UsbManager; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.UserHandle; import android.provider.Settings; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import com.android.server.FgThread; diff --git a/tests/WindowAnimationJank/Android.mk b/tests/WindowAnimationJank/Android.mk index 7800a8078d2a..1c2d16787e88 100644 --- a/tests/WindowAnimationJank/Android.mk +++ b/tests/WindowAnimationJank/Android.mk @@ -26,7 +26,7 @@ LOCAL_PACKAGE_NAME := WindowAnimationJank LOCAL_STATIC_JAVA_LIBRARIES := \ ub-uiautomator \ - ub-janktesthelper \ + androidx.test.janktesthelper \ junit LOCAL_JAVA_LIBRARIES := android.test.base.stubs diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java index 1fb502a09874..6792a8b486af 100644 --- a/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java @@ -17,8 +17,9 @@ package android.windowanimationjank; import android.os.Bundle; -import android.support.test.jank.JankTest; -import android.support.test.jank.GfxMonitor; + +import androidx.test.jank.GfxMonitor; +import androidx.test.jank.JankTest; /** * Detect janks during screen rotation for full-screen activity. Periodically change diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java index bf739fa8da07..a8ace162c4d0 100644 --- a/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java @@ -16,12 +16,10 @@ package android.windowanimationjank; -import java.io.IOException; -import java.util.StringTokenizer; - -import android.support.test.jank.JankTestBase; import android.support.test.uiautomator.UiDevice; +import androidx.test.jank.JankTestBase; + /** * This adds additional system level jank monitor and its result is merged with primary monitor * used in test. diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 1a0e8fa490b3..fbc1a651941b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -939,11 +939,19 @@ public class ConnectivityServiceTest { return mConnected; // Similar trickery } - public void connect() { + private void connect(boolean isAlwaysMetered) { mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); mConnected = true; mConfig = new VpnConfig(); - mConfig.isMetered = false; + mConfig.isMetered = isAlwaysMetered; + } + + public void connectAsAlwaysMetered() { + connect(true /* isAlwaysMetered */); + } + + public void connect() { + connect(false /* isAlwaysMetered */); } @Override @@ -5104,6 +5112,202 @@ public class ConnectivityServiceTest { } @Test + public void testIsActiveNetworkMeteredOverWifi() { + // Returns true by default when no network is available. + assertTrue(mCm.isActiveNetworkMetered()); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + + assertFalse(mCm.isActiveNetworkMetered()); + } + + @Test + public void testIsActiveNetworkMeteredOverCell() { + // Returns true by default when no network is available. + assertTrue(mCm.isActiveNetworkMetered()); + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mCellNetworkAgent.connect(true); + waitForIdle(); + + assertTrue(mCm.isActiveNetworkMetered()); + } + + @Test + public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() { + // Returns true by default when no network is available. + assertTrue(mCm.isActiveNetworkMetered()); + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mCellNetworkAgent.connect(true); + waitForIdle(); + assertTrue(mCm.isActiveNetworkMetered()); + + // Connect VPN network. By default it is using current default network (Cell). + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + final int uid = Process.myUid(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(true); + mMockVpn.connect(); + waitForIdle(); + // Ensure VPN is now the active network. + assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + + // Expect VPN to be metered. + assertTrue(mCm.isActiveNetworkMetered()); + + // Connect WiFi. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + // VPN should still be the active network. + assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + + // Expect VPN to be unmetered as it should now be using WiFi (new default). + assertFalse(mCm.isActiveNetworkMetered()); + + // Disconnecting Cell should not affect VPN's meteredness. + mCellNetworkAgent.disconnect(); + waitForIdle(); + + assertFalse(mCm.isActiveNetworkMetered()); + + // Disconnect WiFi; Now there is no platform default network. + mWiFiNetworkAgent.disconnect(); + waitForIdle(); + + // VPN without any underlying networks is treated as metered. + assertTrue(mCm.isActiveNetworkMetered()); + + vpnNetworkAgent.disconnect(); + mMockVpn.disconnect(); + } + + @Test + public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() { + // Returns true by default when no network is available. + assertTrue(mCm.isActiveNetworkMetered()); + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); + mCellNetworkAgent.connect(true); + waitForIdle(); + assertTrue(mCm.isActiveNetworkMetered()); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + assertFalse(mCm.isActiveNetworkMetered()); + + // Connect VPN network. + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + final int uid = Process.myUid(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(true); + mMockVpn.connect(); + waitForIdle(); + // Ensure VPN is now the active network. + assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + // VPN is using Cell + mService.setUnderlyingNetworksForVpn( + new Network[] { mCellNetworkAgent.getNetwork() }); + waitForIdle(); + + // Expect VPN to be metered. + assertTrue(mCm.isActiveNetworkMetered()); + + // VPN is now using WiFi + mService.setUnderlyingNetworksForVpn( + new Network[] { mWiFiNetworkAgent.getNetwork() }); + waitForIdle(); + + // Expect VPN to be unmetered + assertFalse(mCm.isActiveNetworkMetered()); + + // VPN is using Cell | WiFi. + mService.setUnderlyingNetworksForVpn( + new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() }); + waitForIdle(); + + // Expect VPN to be metered. + assertTrue(mCm.isActiveNetworkMetered()); + + // VPN is using WiFi | Cell. + mService.setUnderlyingNetworksForVpn( + new Network[] { mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork() }); + waitForIdle(); + + // Order should not matter and VPN should still be metered. + assertTrue(mCm.isActiveNetworkMetered()); + + // VPN is not using any underlying networks. + mService.setUnderlyingNetworksForVpn(new Network[0]); + waitForIdle(); + + // VPN without underlying networks is treated as metered. + assertTrue(mCm.isActiveNetworkMetered()); + + vpnNetworkAgent.disconnect(); + mMockVpn.disconnect(); + } + + @Test + public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() { + // Returns true by default when no network is available. + assertTrue(mCm.isActiveNetworkMetered()); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + assertFalse(mCm.isActiveNetworkMetered()); + + // Connect VPN network. + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + final int uid = Process.myUid(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(true); + mMockVpn.connectAsAlwaysMetered(); + waitForIdle(); + assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + + // VPN is tracking current platform default (WiFi). + mService.setUnderlyingNetworksForVpn(null); + waitForIdle(); + + // Despite VPN using WiFi (which is unmetered), VPN itself is marked as always metered. + assertTrue(mCm.isActiveNetworkMetered()); + + // VPN explicitly declares WiFi as its underlying network. + mService.setUnderlyingNetworksForVpn( + new Network[] { mWiFiNetworkAgent.getNetwork() }); + waitForIdle(); + + // Doesn't really matter whether VPN declares its underlying networks explicitly. + assertTrue(mCm.isActiveNetworkMetered()); + + // With WiFi lost, VPN is basically without any underlying networks. And in that case it is + // anyways suppose to be metered. + mWiFiNetworkAgent.disconnect(); + waitForIdle(); + + assertTrue(mCm.isActiveNetworkMetered()); + + vpnNetworkAgent.disconnect(); + } + + @Test public void testNetworkBlockedStatus() { final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 295e3de544ee..52707c28286e 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -196,8 +196,10 @@ class Class(): if "implements" in raw: self.implements = raw[raw.index("implements")+1] + self.implements_all = [self.implements] else: self.implements = None + self.implements_all = [] else: raise ValueError("Unknown signature format: " + sig_format) @@ -224,7 +226,7 @@ class Class(): class Package(): - NAME = re.compile("package(?: .*)? ([A-Za-z.]+)") + NAME = re.compile("package(?: .*)? ([A-Za-z0-9.]+)") def __init__(self, line, raw, blame): self.line = line @@ -364,12 +366,12 @@ class V2LineParser(object): self.parse_matching_paren("<", ">") extends = self.parse_extends() clazz.extends = extends[0] if extends else None - implements = self.parse_implements() - clazz.implements = implements[0] if implements else None + clazz.implements_all = self.parse_implements() # The checks assume that interfaces are always found in implements, which isn't true for # subinterfaces. - if not implements and "interface" in clazz.split: - clazz.implements = clazz.extends + if not clazz.implements_all and "interface" in clazz.split: + clazz.implements_all = [clazz.extends] + clazz.implements = clazz.implements_all[0] if clazz.implements_all else None self.parse_token("{") self.parse_eof() @@ -1249,6 +1251,7 @@ def verify_boolean(clazz): def verify_collections(clazz): """Verifies that collection types are interfaces.""" if clazz.fullname == "android.os.Bundle": return + if clazz.fullname == "android.os.Parcel": return bad = ["java.util.Vector", "java.util.LinkedList", "java.util.ArrayList", "java.util.Stack", "java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"] @@ -1284,9 +1287,9 @@ def verify_exception(clazz): error(clazz, m, "S1", "Methods must not throw generic exceptions") if t in ["android.os.RemoteException"]: - if clazz.name == "android.content.ContentProviderClient": continue - if clazz.name == "android.os.Binder": continue - if clazz.name == "android.os.IBinder": continue + if clazz.fullname == "android.content.ContentProviderClient": continue + if clazz.fullname == "android.os.Binder": continue + if clazz.fullname == "android.os.IBinder": continue error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException") @@ -1653,8 +1656,8 @@ def verify_units(clazz): def verify_closable(clazz): """Verifies that classes are AutoClosable.""" - if clazz.implements == "java.lang.AutoCloseable": return - if clazz.implements == "java.io.Closeable": return + if "java.lang.AutoCloseable" in clazz.implements_all: return + if "java.io.Closeable" in clazz.implements_all: return for m in clazz.methods: if len(m.args) > 0: continue @@ -1853,6 +1856,9 @@ def verify_clone(clazz): def verify_pfd(clazz): """Verify that android APIs use PFD over FD.""" + if clazz.fullname == "android.os.FileUtils" or clazz.fullname == "android.system.Os": + return + examine = clazz.ctors + clazz.methods for m in examine: if m.typ == "java.io.FileDescriptor": diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py index f34492d644ce..5cb43db0b00d 100644 --- a/tools/apilint/apilint_test.py +++ b/tools/apilint/apilint_test.py @@ -242,6 +242,10 @@ class V2ParserTests(unittest.TestCase): cls = self._cls("class Class {") return apilint.Field(cls, 1, raw, '', sig_format=2) + def test_parse_package(self): + pkg = apilint.Package(999, "package wifi.p2p {", None) + self.assertEquals("wifi.p2p", pkg.name) + def test_class(self): cls = self._cls("@Deprecated @IntRange(from=1, to=2) public static abstract class Some.Name extends Super<Class> implements Interface<Class> {") self.assertTrue('deprecated' in cls.split) diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java index 6f588935c44c..ee976287b467 100644 --- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java +++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; @@ -86,20 +87,98 @@ public final class InspectableClassModel { } /** + * Represents a way to access a property, either a getter or a field. + */ + public static final class Accessor { + private final String mName; + private final Type mType; + + /** + * Construct an accessor for a field. + * + * @param name The name of the field + * @return The new accessor + * @see Type#FIELD + */ + static Accessor ofField(String name) { + return new Accessor(name, Type.FIELD); + } + + /** + * Construct an accessor for a getter. + * + * @param name The name of the getter + * @return The new accessor + * @see Type#GETTER + */ + static Accessor ofGetter(String name) { + return new Accessor(name, Type.GETTER); + } + + public Accessor(String name, Type type) { + mName = Objects.requireNonNull(name, "Accessor name must not be null"); + mType = Objects.requireNonNull(type, "Accessor type must not be null"); + } + + public String getName() { + return mName; + } + + public Type getType() { + return mType; + } + + /** + * Get the invocation of this accessor. + * + * Example: {@code "getValue()"} for a getter or {@code "valueField"} for a field. + * + * @return A string representing the invocation of this accessor + */ + public String invocation() { + switch (mType) { + case FIELD: + return mName; + case GETTER: + return String.format("%s()", mName); + default: + throw new NoSuchElementException( + String.format("No such accessor type %s", mType)); + } + } + + public enum Type { + /** + * A property accessed by a public field. + * + * @see #ofField(String) + */ + FIELD, + + /** + * A property accessed by a public getter method. + * + * @see #ofGetter(String) + */ + GETTER + } + } + + /** * Model an inspectable property */ public static final class Property { private final String mName; - private final String mGetter; + private final Accessor mAccessor; private final Type mType; private boolean mAttributeIdInferrableFromR = true; private int mAttributeId = 0; private List<IntEnumEntry> mIntEnumEntries; private List<IntFlagEntry> mIntFlagEntries; - public Property(String name, String getter, Type type) { + public Property(String name, Accessor accessor, Type type) { mName = Objects.requireNonNull(name, "Name must not be null"); - mGetter = Objects.requireNonNull(getter, "Getter must not be null"); + mAccessor = Objects.requireNonNull(accessor, "Accessor must not be null"); mType = Objects.requireNonNull(type, "Type must not be null"); } @@ -129,8 +208,8 @@ public final class InspectableClassModel { return mName; } - public String getGetter() { - return mGetter; + public Accessor getAccessor() { + return mAccessor; } public Type getType() { diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java index 50c79da25eba..6305228cfa36 100644 --- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java +++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java @@ -16,6 +16,7 @@ package android.processor.view.inspector; +import android.processor.view.inspector.InspectableClassModel.Accessor; import android.processor.view.inspector.InspectableClassModel.IntEnumEntry; import android.processor.view.inspector.InspectableClassModel.IntFlagEntry; import android.processor.view.inspector.InspectableClassModel.Property; @@ -93,16 +94,15 @@ public final class InspectablePropertyProcessor implements ModelProcessor { try { final AnnotationMirror annotation = mAnnotationUtils.exactlyOneMirror(mQualifiedName, element); - final ExecutableElement getter = ensureGetter(element); - final Property property = buildProperty(getter, annotation); + final Property property = buildProperty(element, annotation); model.getProperty(property.getName()).ifPresent(p -> { throw new ProcessingException( String.format( - "Property \"%s\" is already defined on #%s().", + "Property \"%s\" is already defined on #%s.", p.getName(), - p.getGetter()), - getter, + p.getAccessor().invocation()), + element, annotation); }); @@ -112,26 +112,79 @@ public final class InspectablePropertyProcessor implements ModelProcessor { } } + /** - * Check that an element is shaped like a getter. + * Build a {@link Property} from a getter and an inspectable property annotation. * - * @param element An element that hopefully represents a getter - * @return An {@link ExecutableElement} that represents a getter method. - * @throws ProcessingException if the element isn't a getter + * @param accessor An element representing the getter or public field to build from + * @param annotation A mirror of an inspectable property-shaped annotation + * @return A property for the getter and annotation + * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled */ - private ExecutableElement ensureGetter(Element element) { - if (element.getKind() != ElementKind.METHOD) { - throw new ProcessingException( - String.format("Expected a method, got a %s", element.getKind()), - element); + private Property buildProperty(Element accessor, AnnotationMirror annotation) { + final Property property; + final Optional<String> nameFromAnnotation = mAnnotationUtils + .typedValueByName("name", String.class, accessor, annotation); + + validateModifiers(accessor); + + switch (accessor.getKind()) { + case FIELD: + property = new Property( + nameFromAnnotation.orElseGet(() -> accessor.getSimpleName().toString()), + Accessor.ofField(accessor.getSimpleName().toString()), + determinePropertyType(accessor, annotation)); + break; + case METHOD: + final ExecutableElement getter = ensureGetter(accessor); + + property = new Property( + nameFromAnnotation.orElseGet(() -> inferPropertyNameFromGetter(getter)), + Accessor.ofGetter(getter.getSimpleName().toString()), + determinePropertyType(getter, annotation)); + break; + default: + throw new ProcessingException( + String.format( + "Property must either be a getter method or a field, got %s.", + accessor.getKind() + ), + accessor, + annotation); } - final ExecutableElement method = (ExecutableElement) element; - final Set<Modifier> modifiers = method.getModifiers(); + mAnnotationUtils + .typedValueByName("hasAttributeId", Boolean.class, accessor, annotation) + .ifPresent(property::setAttributeIdInferrableFromR); - if (modifiers.contains(Modifier.PRIVATE)) { + mAnnotationUtils + .typedValueByName("attributeId", Integer.class, accessor, annotation) + .ifPresent(property::setAttributeId); + + switch (property.getType()) { + case INT_ENUM: + property.setIntEnumEntries(processEnumMapping(accessor, annotation)); + break; + case INT_FLAG: + property.setIntFlagEntries(processFlagMapping(accessor, annotation)); + break; + } + + return property; + } + + /** + * Validates that an element is public, concrete, and non-static. + * + * @param element The element to check + * @throws ProcessingException If the element's modifiers are invalid + */ + private void validateModifiers(Element element) { + final Set<Modifier> modifiers = element.getModifiers(); + + if (!modifiers.contains(Modifier.PUBLIC)) { throw new ProcessingException( - "Property getter methods must not be private.", + "Property getter methods and fields must be public.", element); } @@ -143,10 +196,28 @@ public final class InspectablePropertyProcessor implements ModelProcessor { if (modifiers.contains(Modifier.STATIC)) { throw new ProcessingException( - "Property getter methods must not be static.", + "Property getter methods and fields must not be static.", + element); + } + } + + /** + * Check that an element is shaped like a getter. + * + * @param element An element that hopefully represents a getter + * @return An {@link ExecutableElement} that represents a getter method. + * @throws ProcessingException if the element isn't a getter + */ + private ExecutableElement ensureGetter(Element element) { + if (element.getKind() != ElementKind.METHOD) { + throw new ProcessingException( + String.format("Expected a method, got a %s", element.getKind()), element); } + final ExecutableElement method = (ExecutableElement) element; + + if (!method.getParameters().isEmpty()) { throw new ProcessingException( String.format( @@ -171,77 +242,41 @@ public final class InspectablePropertyProcessor implements ModelProcessor { return method; } - /** - * Build a {@link Property} from a getter and an inspectable property annotation. - * - * @param getter An element representing the getter to build from - * @param annotation A mirror of an inspectable property-shaped annotation - * @return A property for the getter and annotation - * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled - */ - private Property buildProperty(ExecutableElement getter, AnnotationMirror annotation) { - final String name = mAnnotationUtils - .typedValueByName("name", String.class, getter, annotation) - .orElseGet(() -> inferPropertyNameFromGetter(getter)); - - final Property property = new Property( - name, - getter.getSimpleName().toString(), - determinePropertyType(getter, annotation)); - - mAnnotationUtils - .typedValueByName("hasAttributeId", Boolean.class, getter, annotation) - .ifPresent(property::setAttributeIdInferrableFromR); - - mAnnotationUtils - .typedValueByName("attributeId", Integer.class, getter, annotation) - .ifPresent(property::setAttributeId); - - switch (property.getType()) { - case INT_ENUM: - property.setIntEnumEntries(processEnumMapping(getter, annotation)); - break; - case INT_FLAG: - property.setIntFlagEntries(processFlagMapping(getter, annotation)); - break; - } - - return property; - } /** * Determine the property type from the annotation, return type, or context clues. * - * @param getter An element representing the getter to build from + * @param accessor An element representing the getter or field to determine the type of * @param annotation A mirror of an inspectable property-shaped annotation * @return The resolved property type * @throws ProcessingException If the property type cannot be resolved or is invalid * @see android.view.inspector.InspectableProperty#valueType() */ private Property.Type determinePropertyType( - ExecutableElement getter, + Element accessor, AnnotationMirror annotation) { final String valueType = mAnnotationUtils - .untypedValueByName("valueType", getter, annotation) + .untypedValueByName("valueType", accessor, annotation) .map(Object::toString) .orElse("INFERRED"); - final Property.Type returnType = convertReturnTypeToPropertyType(getter); + final Property.Type accessorType = + convertTypeMirrorToPropertyType(extractReturnOrFieldType(accessor), accessor); - final boolean hasColor = hasColorAnnotation(getter); + final boolean hasColor = hasColorAnnotation(accessor); final Optional<AnnotationValue> enumMapping = mAnnotationUtils.valueByName("enumMapping", annotation); final Optional<AnnotationValue> flagMapping = mAnnotationUtils.valueByName("flagMapping", annotation); - if (returnType != Property.Type.INT) { + if (accessorType != Property.Type.INT) { enumMapping.ifPresent(value -> { throw new ProcessingException( String.format( "Can only use enumMapping on int types, got %s.", - returnType.toString().toLowerCase()), - getter, + accessorType.toString().toLowerCase()), + accessor, annotation, value); }); @@ -249,8 +284,8 @@ public final class InspectablePropertyProcessor implements ModelProcessor { throw new ProcessingException( String.format( "Can only use flagMapping on int types, got %s.", - returnType.toString().toLowerCase()), - getter, + accessorType.toString().toLowerCase()), + accessor, annotation, value); }); @@ -262,14 +297,14 @@ public final class InspectablePropertyProcessor implements ModelProcessor { enumMapping.ifPresent(value -> { throw new ProcessingException( "Cannot use enumMapping on a color type.", - getter, + accessor, annotation, value); }); flagMapping.ifPresent(value -> { throw new ProcessingException( "Cannot use flagMapping on a color type.", - getter, + accessor, annotation, value); }); @@ -278,7 +313,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor { flagMapping.ifPresent(value -> { throw new ProcessingException( "Cannot use flagMapping and enumMapping simultaneously.", - getter, + accessor, annotation, value); }); @@ -286,12 +321,12 @@ public final class InspectablePropertyProcessor implements ModelProcessor { } else if (flagMapping.isPresent()) { return Property.Type.INT_FLAG; } else { - return returnType; + return accessorType; } case "NONE": - return returnType; + return accessorType; case "COLOR": - switch (returnType) { + switch (accessorType) { case COLOR: case INT: case LONG: @@ -299,37 +334,58 @@ public final class InspectablePropertyProcessor implements ModelProcessor { default: throw new ProcessingException( "Color must be a long, integer, or android.graphics.Color", - getter, + accessor, annotation); } case "GRAVITY": - requirePackedIntToReturnInt("Gravity", returnType, getter, annotation); + requirePackedIntToBeInt("Gravity", accessorType, accessor, annotation); return Property.Type.GRAVITY; case "INT_ENUM": - requirePackedIntToReturnInt("IntEnum", returnType, getter, annotation); + requirePackedIntToBeInt("IntEnum", accessorType, accessor, annotation); return Property.Type.INT_ENUM; case "INT_FLAG": - requirePackedIntToReturnInt("IntFlag", returnType, getter, annotation); + requirePackedIntToBeInt("IntFlag", accessorType, accessor, annotation); return Property.Type.INT_FLAG; default: throw new ProcessingException( String.format("Unknown value type enumeration value: %s", valueType), - getter, + accessor, annotation); } } /** - * Get a property type from the return type of a getter. + * Get the type of a field or the return type of a method. * - * @param getter The getter to extract the return type of + * @param element The element to extract a {@link TypeMirror} from + * @return The return or field type of the element + * @throws ProcessingException If the element is not a field or a method + */ + private TypeMirror extractReturnOrFieldType(Element element) { + switch (element.getKind()) { + case FIELD: + return element.asType(); + case METHOD: + return ((ExecutableElement) element).getReturnType(); + default: + throw new ProcessingException( + String.format( + "Unable to determine the type of a %s.", + element.getKind()), + element); + } + } + + /** + * Get a property type from a type mirror + * + * @param typeMirror The type mirror to convert to a property type + * @param element The element to be used for exceptions * @return The property type returned by the getter * @throws ProcessingException If the return type is not a primitive or an object */ - private Property.Type convertReturnTypeToPropertyType(ExecutableElement getter) { - final TypeMirror returnType = getter.getReturnType(); - - switch (unboxType(returnType)) { + private Property.Type convertTypeMirrorToPropertyType(TypeMirror typeMirror, Element element) { + switch (unboxType(typeMirror)) { case BOOLEAN: return Property.Type.BOOLEAN; case BYTE: @@ -347,7 +403,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor { case SHORT: return Property.Type.SHORT; case DECLARED: - if (isColorType(returnType)) { + if (isColorType(typeMirror)) { return Property.Type.COLOR; } else { return Property.Type.OBJECT; @@ -356,24 +412,24 @@ public final class InspectablePropertyProcessor implements ModelProcessor { return Property.Type.OBJECT; default: throw new ProcessingException( - String.format("Unsupported return type %s.", returnType), - getter); + String.format("Unsupported property type %s.", typeMirror), + element); } } /** * Require that a value type packed into an integer be on a getter that returns an int. * - * @param typeName The name of the type to use in the exception + * @param typeName The name of the type to use in the exception * @param returnType The return type of the getter to check - * @param getter The getter, to use in the exception + * @param accessor The getter, to use in the exception * @param annotation The annotation, to use in the exception * @throws ProcessingException If the return type is not an int */ - private static void requirePackedIntToReturnInt( + private static void requirePackedIntToBeInt( String typeName, Property.Type returnType, - ExecutableElement getter, + Element accessor, AnnotationMirror annotation) { if (returnType != Property.Type.INT) { throw new ProcessingException( @@ -381,7 +437,7 @@ public final class InspectablePropertyProcessor implements ModelProcessor { "%s can only be defined on a method that returns int, got %s.", typeName, returnType.toString().toLowerCase()), - getter, + accessor, annotation); } } @@ -393,21 +449,21 @@ public final class InspectablePropertyProcessor implements ModelProcessor { * not considered to be annotated, nor is a {@code long} annotated with * {@link android.annotation.ColorInt}. * - * @param getter The getter to query + * @param accessor The getter or field to query * @return True if the getter has a color annotation, false otherwise */ - private boolean hasColorAnnotation(ExecutableElement getter) { - switch (unboxType(getter.getReturnType())) { + private boolean hasColorAnnotation(Element accessor) { + switch (unboxType(extractReturnOrFieldType(accessor))) { case INT: for (String name : COLOR_INT_ANNOTATION_NAMES) { - if (mAnnotationUtils.hasAnnotation(getter, name)) { + if (mAnnotationUtils.hasAnnotation(accessor, name)) { return true; } } return false; case LONG: for (String name : COLOR_LONG_ANNOTATION_NAMES) { - if (mAnnotationUtils.hasAnnotation(getter, name)) { + if (mAnnotationUtils.hasAnnotation(accessor, name)) { return true; } } @@ -452,40 +508,40 @@ public final class InspectablePropertyProcessor implements ModelProcessor { * * @see android.view.inspector.IntEnumMapping * @see android.view.inspector.InspectableProperty#enumMapping() - * @param getter The getter of the property, used for exceptions + * @param accessor The accessor of the property, used for exceptions * @param annotation The {@link android.view.inspector.InspectableProperty} annotation to * extract enum mapping values from. * @return A list of int enum entries, in the order specified in source * @throws ProcessingException if mapping doesn't exist or is invalid */ private List<IntEnumEntry> processEnumMapping( - ExecutableElement getter, + Element accessor, AnnotationMirror annotation) { List<AnnotationMirror> enumAnnotations = mAnnotationUtils.typedArrayValuesByName( - "enumMapping", AnnotationMirror.class, getter, annotation); + "enumMapping", AnnotationMirror.class, accessor, annotation); List<IntEnumEntry> enumEntries = new ArrayList<>(enumAnnotations.size()); if (enumAnnotations.isEmpty()) { throw new ProcessingException( - "Encountered an empty array for enumMapping", getter, annotation); + "Encountered an empty array for enumMapping", accessor, annotation); } for (AnnotationMirror enumAnnotation : enumAnnotations) { final String name = mAnnotationUtils.typedValueByName( - "name", String.class, getter, enumAnnotation) + "name", String.class, accessor, enumAnnotation) .orElseThrow(() -> { throw new ProcessingException( "Name is required for @EnumMap", - getter, + accessor, enumAnnotation); }); final int value = mAnnotationUtils.typedValueByName( - "value", Integer.class, getter, enumAnnotation) + "value", Integer.class, accessor, enumAnnotation) .orElseThrow(() -> { throw new ProcessingException( "Value is required for @EnumMap", - getter, + accessor, enumAnnotation); }); @@ -504,45 +560,45 @@ public final class InspectablePropertyProcessor implements ModelProcessor { * * @see android.view.inspector.IntFlagMapping * @see android.view.inspector.InspectableProperty#flagMapping() - * @param getter The getter of the property, used for exceptions + * @param accessor The accessor of the property, used for exceptions * @param annotation The {@link android.view.inspector.InspectableProperty} annotation to * extract flag mapping values from. * @return A list of int flags entries, in the order specified in source * @throws ProcessingException if mapping doesn't exist or is invalid */ private List<IntFlagEntry> processFlagMapping( - ExecutableElement getter, + Element accessor, AnnotationMirror annotation) { List<AnnotationMirror> flagAnnotations = mAnnotationUtils.typedArrayValuesByName( - "flagMapping", AnnotationMirror.class, getter, annotation); + "flagMapping", AnnotationMirror.class, accessor, annotation); List<IntFlagEntry> flagEntries = new ArrayList<>(flagAnnotations.size()); if (flagAnnotations.isEmpty()) { throw new ProcessingException( - "Encountered an empty array for flagMapping", getter, annotation); + "Encountered an empty array for flagMapping", accessor, annotation); } for (AnnotationMirror flagAnnotation : flagAnnotations) { final String name = mAnnotationUtils.typedValueByName( - "name", String.class, getter, flagAnnotation) + "name", String.class, accessor, flagAnnotation) .orElseThrow(() -> { throw new ProcessingException( "Name is required for @FlagMap", - getter, + accessor, flagAnnotation); }); final int target = mAnnotationUtils.typedValueByName( - "target", Integer.class, getter, flagAnnotation) + "target", Integer.class, accessor, flagAnnotation) .orElseThrow(() -> { throw new ProcessingException( "Target is required for @FlagMap", - getter, + accessor, flagAnnotation); }); final Optional<Integer> mask = mAnnotationUtils.typedValueByName( - "mask", Integer.class, getter, flagAnnotation); + "mask", Integer.class, accessor, flagAnnotation); if (mask.isPresent()) { flagEntries.add(new IntFlagEntry(name, target, mask.get())); diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java index 7b04645e9f44..1ab9914d3aed 100644 --- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java +++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java @@ -16,6 +16,7 @@ package android.processor.view.inspector; + import android.processor.view.inspector.InspectableClassModel.IntEnumEntry; import android.processor.view.inspector.InspectableClassModel.IntFlagEntry; import android.processor.view.inspector.InspectableClassModel.Property; @@ -268,10 +269,10 @@ public final class InspectionCompanionGenerator { for (PropertyIdField propertyIdField : propertyIdFields) { builder.addStatement( - "propertyReader.read$L($N, node.$L())", + "propertyReader.read$L($N, node.$L)", methodSuffixForPropertyType(propertyIdField.mProperty.getType()), propertyIdField.mFieldSpec, - propertyIdField.mProperty.getGetter()); + propertyIdField.mProperty.getAccessor().invocation()); } return builder.build(); diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java index f6d8bb0939db..35f0fcf9bcae 100644 --- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java +++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java @@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; + +import android.processor.view.inspector.InspectableClassModel.Accessor; import android.processor.view.inspector.InspectableClassModel.IntEnumEntry; import android.processor.view.inspector.InspectableClassModel.IntFlagEntry; import android.processor.view.inspector.InspectableClassModel.Property; @@ -86,7 +88,7 @@ public class InspectionCompanionGeneratorTest { @Test public void testNoAttributeId() { - final Property property = new Property( + final Property property = addProperty( "noAttributeProperty", "getNoAttributeProperty", Property.Type.INT); @@ -98,19 +100,18 @@ public class InspectionCompanionGeneratorTest { @Test public void testSuppliedAttributeId() { - final Property property = new Property( + final Property property = addProperty( "suppliedAttributeProperty", "getSuppliedAttributeProperty", Property.Type.INT); property.setAttributeId(0xdecafbad); - mModel.putProperty(property); assertGeneratedFileEquals("SuppliedAttributeId"); } @Test public void testIntEnum() { - final Property property = new Property( + final Property property = addProperty( "intEnumProperty", "getIntEnumProperty", Property.Type.INT_ENUM); @@ -127,7 +128,7 @@ public class InspectionCompanionGeneratorTest { @Test public void testIntFlag() { - final Property property = new Property( + final Property property = addProperty( "intFlag", "getIntFlag", Property.Type.INT_FLAG); @@ -139,13 +140,21 @@ public class InspectionCompanionGeneratorTest { new IntFlagEntry("WARP", 0x4) )); - mModel.putProperty(property); - assertGeneratedFileEquals("IntFlag"); } + @Test + public void testFieldProperty() { + mModel.putProperty(new Property( + "fieldProperty", + Accessor.ofField("fieldProperty"), + Property.Type.INT)); + + assertGeneratedFileEquals("FieldProperty"); + } + private Property addProperty(String name, String getter, Property.Type type) { - final Property property = new Property(name, getter, type); + final Property property = new Property(name, Accessor.ofGetter(getter), type); mModel.putProperty(property); return property; } diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt new file mode 100644 index 000000000000..a44c43ec0b21 --- /dev/null +++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt @@ -0,0 +1,39 @@ +package com.android.node; + +import android.R; +import android.view.inspector.InspectionCompanion; +import android.view.inspector.PropertyMapper; +import android.view.inspector.PropertyReader; +import java.lang.Override; + +/** + * Inspection companion for {@link TestNode}. + * + * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator} + * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}. + */ +public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> { + /** + * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped. + */ + private boolean mPropertiesMapped = false; + + /** + * Property ID of {@code fieldProperty}. + */ + private int mFieldPropertyId; + + @Override + public void mapProperties(PropertyMapper propertyMapper) { + mFieldPropertyId = propertyMapper.mapInt("fieldProperty", R.attr.fieldProperty); + mPropertiesMapped = true; + } + + @Override + public void readProperties(TestNode node, PropertyReader propertyReader) { + if (!mPropertiesMapped) { + throw new InspectionCompanion.UninitializedPropertyMapException(); + } + propertyReader.readInt(mFieldPropertyId, node.fieldProperty); + } +} |